deltachat-rpc-client 1.156.2__tar.gz → 1.157.1__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.
- {deltachat_rpc_client-1.156.2/src/deltachat_rpc_client.egg-info → deltachat_rpc_client-1.157.1}/PKG-INFO +1 -1
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/pyproject.toml +1 -1
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/account.py +47 -2
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/contact.py +1 -1
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1/src/deltachat_rpc_client.egg-info}/PKG-INFO +1 -1
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/tests/test_chatlist_events.py +1 -5
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/tests/test_securejoin.py +2 -5
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/tests/test_something.py +29 -10
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/LICENSE +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/README.md +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/setup.cfg +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/__init__.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/_utils.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/chat.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/client.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/const.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/deltachat.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/events.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/message.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/py.typed +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/pytestplugin.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/rpc.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client.egg-info/SOURCES.txt +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client.egg-info/dependency_links.txt +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client.egg-info/entry_points.txt +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client.egg-info/top_level.txt +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/tests/test_account_events.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/tests/test_iroh_webxdc.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/tests/test_key_transfer.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/tests/test_vcard.py +0 -0
- {deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/tests/test_webxdc.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deltachat-rpc-client"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.157.1"
|
|
8
8
|
description = "Python client for Delta Chat core JSON-RPC interface"
|
|
9
9
|
classifiers = [
|
|
10
10
|
"Development Status :: 5 - Production/Stable",
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/account.py
RENAMED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from tempfile import TemporaryDirectory
|
|
4
6
|
from typing import TYPE_CHECKING, Optional, Union
|
|
5
7
|
from warnings import warn
|
|
6
8
|
|
|
@@ -38,6 +40,16 @@ class Account:
|
|
|
38
40
|
"""Remove the account."""
|
|
39
41
|
self._rpc.remove_account(self.id)
|
|
40
42
|
|
|
43
|
+
def clone(self) -> "Account":
|
|
44
|
+
"""Clone given account."""
|
|
45
|
+
with TemporaryDirectory() as tmp_dir:
|
|
46
|
+
tmp_path = Path(tmp_dir)
|
|
47
|
+
self.export_backup(tmp_path)
|
|
48
|
+
files = list(tmp_path.glob("*.tar"))
|
|
49
|
+
new_account = self.manager.add_account()
|
|
50
|
+
new_account.import_backup(files[0])
|
|
51
|
+
return new_account
|
|
52
|
+
|
|
41
53
|
def start_io(self) -> None:
|
|
42
54
|
"""Start the account I/O."""
|
|
43
55
|
self._rpc.start_io(self.id)
|
|
@@ -83,6 +95,10 @@ class Account:
|
|
|
83
95
|
return self.get_config("selfavatar")
|
|
84
96
|
|
|
85
97
|
def check_qr(self, qr):
|
|
98
|
+
"""Parse QR code contents.
|
|
99
|
+
|
|
100
|
+
This function takes the raw text scanned
|
|
101
|
+
and checks what can be done with it."""
|
|
86
102
|
return self._rpc.check_qr(self.id, qr)
|
|
87
103
|
|
|
88
104
|
def set_config_from_qr(self, qr: str):
|
|
@@ -118,11 +134,28 @@ class Account:
|
|
|
118
134
|
obj = obj.get_snapshot().address
|
|
119
135
|
return Contact(self, self._rpc.create_contact(self.id, obj, name))
|
|
120
136
|
|
|
137
|
+
def make_vcard(self, contacts: list[Contact]) -> str:
|
|
138
|
+
"""Create vCard with the given contacts."""
|
|
139
|
+
assert all(contact.account == self for contact in contacts)
|
|
140
|
+
contact_ids = [contact.id for contact in contacts]
|
|
141
|
+
return self._rpc.make_vcard(self.id, contact_ids)
|
|
142
|
+
|
|
143
|
+
def import_vcard(self, vcard: str) -> list[Contact]:
|
|
144
|
+
"""Import vCard.
|
|
145
|
+
|
|
146
|
+
Return created or modified contacts in the order they appear in vCard."""
|
|
147
|
+
contact_ids = self._rpc.import_vcard_contents(self.id, vcard)
|
|
148
|
+
return [Contact(self, contact_id) for contact_id in contact_ids]
|
|
149
|
+
|
|
121
150
|
def create_chat(self, account: "Account") -> Chat:
|
|
122
|
-
|
|
123
|
-
contact = self.
|
|
151
|
+
vcard = account.self_contact.make_vcard()
|
|
152
|
+
[contact] = self.import_vcard(vcard)
|
|
124
153
|
return contact.create_chat()
|
|
125
154
|
|
|
155
|
+
def get_device_chat(self) -> Chat:
|
|
156
|
+
"""Return device chat."""
|
|
157
|
+
return self.device_contact.create_chat()
|
|
158
|
+
|
|
126
159
|
def get_contact_by_id(self, contact_id: int) -> Contact:
|
|
127
160
|
"""Return Contact instance for the given contact ID."""
|
|
128
161
|
return Contact(self, contact_id)
|
|
@@ -183,6 +216,11 @@ class Account:
|
|
|
183
216
|
"""This account's identity as a Contact."""
|
|
184
217
|
return Contact(self, SpecialContactId.SELF)
|
|
185
218
|
|
|
219
|
+
@property
|
|
220
|
+
def device_contact(self) -> Chat:
|
|
221
|
+
"""This account's device contact."""
|
|
222
|
+
return Contact(self, SpecialContactId.DEVICE)
|
|
223
|
+
|
|
186
224
|
def get_chatlist(
|
|
187
225
|
self,
|
|
188
226
|
query: Optional[str] = None,
|
|
@@ -308,6 +346,13 @@ class Account:
|
|
|
308
346
|
if event.kind == EventType.MSGS_CHANGED:
|
|
309
347
|
return event
|
|
310
348
|
|
|
349
|
+
def wait_for_msgs_noticed_event(self):
|
|
350
|
+
"""Wait for messages noticed event and return it."""
|
|
351
|
+
while True:
|
|
352
|
+
event = self.wait_for_event()
|
|
353
|
+
if event.kind == EventType.MSGS_NOTICED:
|
|
354
|
+
return event
|
|
355
|
+
|
|
311
356
|
def wait_for_incoming_msg(self):
|
|
312
357
|
"""Wait for incoming message and return it.
|
|
313
358
|
|
|
@@ -157,11 +157,7 @@ def get_multi_account_test_setup(acfactory: ACFactory) -> [Account, Account, Acc
|
|
|
157
157
|
|
|
158
158
|
bob.wait_for_incoming_msg_event()
|
|
159
159
|
|
|
160
|
-
alice_second_device
|
|
161
|
-
|
|
162
|
-
alice._rpc.provide_backup.future(alice.id)
|
|
163
|
-
backup_code = alice._rpc.get_backup_qr(alice.id)
|
|
164
|
-
alice_second_device._rpc.get_backup(alice_second_device.id, backup_code)
|
|
160
|
+
alice_second_device = alice.clone()
|
|
165
161
|
alice_second_device.start_io()
|
|
166
162
|
alice.clear_all_events()
|
|
167
163
|
alice_second_device.clear_all_events()
|
|
@@ -60,15 +60,12 @@ def test_qr_setup_contact_svg(acfactory) -> None:
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
@pytest.mark.parametrize("protect", [True, False])
|
|
63
|
-
def test_qr_securejoin(acfactory, protect
|
|
63
|
+
def test_qr_securejoin(acfactory, protect):
|
|
64
64
|
alice, bob, fiona = acfactory.get_online_accounts(3)
|
|
65
65
|
|
|
66
66
|
# Setup second device for Alice
|
|
67
67
|
# to test observing securejoin protocol.
|
|
68
|
-
alice.
|
|
69
|
-
files = list(tmp_path.glob("*.tar"))
|
|
70
|
-
alice2 = acfactory.get_unconfigured_account()
|
|
71
|
-
alice2.import_backup(files[0])
|
|
68
|
+
alice2 = alice.clone()
|
|
72
69
|
|
|
73
70
|
logging.info("Alice creates a group")
|
|
74
71
|
alice_chat = alice.create_group("Group", protect=protect)
|
|
@@ -287,12 +287,9 @@ def test_message(acfactory) -> None:
|
|
|
287
287
|
assert reactions == snapshot.reactions
|
|
288
288
|
|
|
289
289
|
|
|
290
|
-
def test_reaction_seen_on_another_dev(acfactory
|
|
290
|
+
def test_reaction_seen_on_another_dev(acfactory) -> None:
|
|
291
291
|
alice, bob = acfactory.get_online_accounts(2)
|
|
292
|
-
alice.
|
|
293
|
-
files = list(tmp_path.glob("*.tar"))
|
|
294
|
-
alice2 = acfactory.get_unconfigured_account()
|
|
295
|
-
alice2.import_backup(files[0])
|
|
292
|
+
alice2 = alice.clone()
|
|
296
293
|
alice2.start_io()
|
|
297
294
|
|
|
298
295
|
bob_addr = bob.get_config("addr")
|
|
@@ -661,7 +658,7 @@ def test_download_limit_chat_assignment(acfactory, tmp_path, n_accounts):
|
|
|
661
658
|
assert snapshot.chat == bob_chat_alice
|
|
662
659
|
|
|
663
660
|
|
|
664
|
-
def test_markseen_contact_request(acfactory
|
|
661
|
+
def test_markseen_contact_request(acfactory):
|
|
665
662
|
"""
|
|
666
663
|
Test that seen status is synchronized for contact request messages
|
|
667
664
|
even though read receipt is not sent.
|
|
@@ -669,10 +666,7 @@ def test_markseen_contact_request(acfactory, tmp_path):
|
|
|
669
666
|
alice, bob = acfactory.get_online_accounts(2)
|
|
670
667
|
|
|
671
668
|
# Bob sets up a second device.
|
|
672
|
-
bob.
|
|
673
|
-
files = list(tmp_path.glob("*.tar"))
|
|
674
|
-
bob2 = acfactory.get_unconfigured_account()
|
|
675
|
-
bob2.import_backup(files[0])
|
|
669
|
+
bob2 = bob.clone()
|
|
676
670
|
bob2.start_io()
|
|
677
671
|
|
|
678
672
|
alice_chat_bob = alice.create_chat(bob)
|
|
@@ -716,3 +710,28 @@ def test_configured_imap_certificate_checks(acfactory):
|
|
|
716
710
|
# Core 1.142.4, 1.142.5 and 1.142.6 saved this value due to bug.
|
|
717
711
|
# This test is a regression test to prevent this happening again.
|
|
718
712
|
assert configured_certificate_checks != "0"
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
def test_no_old_msg_is_fresh(acfactory):
|
|
716
|
+
ac1, ac2 = acfactory.get_online_accounts(2)
|
|
717
|
+
ac1_clone = ac1.clone()
|
|
718
|
+
ac1_clone.start_io()
|
|
719
|
+
|
|
720
|
+
ac1.create_chat(ac2)
|
|
721
|
+
ac1_clone_chat = ac1_clone.create_chat(ac2)
|
|
722
|
+
|
|
723
|
+
ac1.get_device_chat().mark_noticed()
|
|
724
|
+
|
|
725
|
+
logging.info("Send a first message from ac2 to ac1 and check that it's 'fresh'")
|
|
726
|
+
first_msg = ac2.create_chat(ac1).send_text("Hi")
|
|
727
|
+
ac1.wait_for_incoming_msg_event()
|
|
728
|
+
assert ac1.create_chat(ac2).get_fresh_message_count() == 1
|
|
729
|
+
assert len(list(ac1.get_fresh_messages())) == 1
|
|
730
|
+
|
|
731
|
+
logging.info("Send a message from ac1_clone to ac2 and check that ac1 marks the first message as 'noticed'")
|
|
732
|
+
ac1_clone_chat.send_text("Hi back")
|
|
733
|
+
ev = ac1.wait_for_msgs_noticed_event()
|
|
734
|
+
|
|
735
|
+
assert ev.chat_id == first_msg.get_snapshot().chat_id
|
|
736
|
+
assert ac1.create_chat(ac2).get_fresh_message_count() == 0
|
|
737
|
+
assert len(list(ac1.get_fresh_messages())) == 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/__init__.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/_utils.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/chat.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/client.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/const.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/deltachat.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/events.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/message.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
{deltachat_rpc_client-1.156.2 → deltachat_rpc_client-1.157.1}/src/deltachat_rpc_client/rpc.py
RENAMED
|
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
|