deltachat-rpc-client 2.27.0__tar.gz → 2.28.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.
Files changed (35) hide show
  1. {deltachat_rpc_client-2.27.0/src/deltachat_rpc_client.egg-info → deltachat_rpc_client-2.28.0}/PKG-INFO +1 -1
  2. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/pyproject.toml +1 -1
  3. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/account.py +4 -0
  4. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/pytestplugin.py +8 -2
  5. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0/src/deltachat_rpc_client.egg-info}/PKG-INFO +1 -1
  6. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client.egg-info/SOURCES.txt +1 -0
  7. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_folders.py +1 -1
  8. deltachat_rpc_client-2.28.0/tests/test_multitransport.py +158 -0
  9. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_securejoin.py +8 -8
  10. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_something.py +7 -6
  11. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/LICENSE +0 -0
  12. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/README.md +0 -0
  13. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/setup.cfg +0 -0
  14. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/__init__.py +0 -0
  15. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/_utils.py +0 -0
  16. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/chat.py +0 -0
  17. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/client.py +0 -0
  18. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/const.py +0 -0
  19. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/contact.py +0 -0
  20. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/deltachat.py +0 -0
  21. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/events.py +0 -0
  22. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/message.py +0 -0
  23. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/py.typed +0 -0
  24. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client/rpc.py +0 -0
  25. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client.egg-info/dependency_links.txt +0 -0
  26. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client.egg-info/entry_points.txt +0 -0
  27. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/src/deltachat_rpc_client.egg-info/top_level.txt +0 -0
  28. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_account_events.py +0 -0
  29. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_calls.py +0 -0
  30. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_chatlist_events.py +0 -0
  31. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_iroh_webxdc.py +0 -0
  32. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_key_transfer.py +0 -0
  33. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_multidevice.py +0 -0
  34. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_vcard.py +0 -0
  35. {deltachat_rpc_client-2.27.0 → deltachat_rpc_client-2.28.0}/tests/test_webxdc.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deltachat-rpc-client
3
- Version: 2.27.0
3
+ Version: 2.28.0
4
4
  Summary: Python client for Delta Chat core JSON-RPC interface
5
5
  Classifier: Development Status :: 5 - Production/Stable
6
6
  Classifier: Intended Audience :: Developers
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "deltachat-rpc-client"
7
- version = "2.27.0"
7
+ version = "2.28.0"
8
8
  description = "Python client for Delta Chat core JSON-RPC interface"
9
9
  classifiers = [
10
10
  "Development Status :: 5 - Production/Stable",
@@ -130,6 +130,10 @@ class Account:
130
130
  """Add a new transport using a QR code."""
131
131
  yield self._rpc.add_transport_from_qr.future(self.id, qr)
132
132
 
133
+ def delete_transport(self, addr: str):
134
+ """Delete a transport."""
135
+ self._rpc.delete_transport(self.id, addr)
136
+
133
137
  @futuremethod
134
138
  def list_transports(self):
135
139
  """Return the list of all email accounts that are used as a transport in the current profile."""
@@ -40,12 +40,17 @@ class ACFactory:
40
40
  username = "ci-" + "".join(random.choice("2345789acdefghjkmnpqrstuvwxyz") for i in range(6))
41
41
  return f"{username}@{domain}", f"{username}${username}"
42
42
 
43
+ def get_account_qr(self):
44
+ """Return "dcaccount:" QR code for testing chatmail relay."""
45
+ domain = os.getenv("CHATMAIL_DOMAIN")
46
+ return f"dcaccount:{domain}"
47
+
43
48
  @futuremethod
44
49
  def new_configured_account(self):
45
50
  """Create a new configured account."""
46
51
  account = self.get_unconfigured_account()
47
- domain = os.getenv("CHATMAIL_DOMAIN")
48
- yield account.add_transport_from_qr.future(f"dcaccount:{domain}")
52
+ qr = self.get_account_qr()
53
+ yield account.add_transport_from_qr.future(qr)
49
54
 
50
55
  assert account.is_configured()
51
56
  return account
@@ -77,6 +82,7 @@ class ACFactory:
77
82
  ac_clone = self.get_unconfigured_account()
78
83
  for transport in transports:
79
84
  ac_clone.add_or_update_transport(transport)
85
+ ac_clone.bring_online()
80
86
  return ac_clone
81
87
 
82
88
  def get_accepted_chat(self, ac1: Account, ac2: Account) -> Chat:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deltachat-rpc-client
3
- Version: 2.27.0
3
+ Version: 2.28.0
4
4
  Summary: Python client for Delta Chat core JSON-RPC interface
5
5
  Classifier: Development Status :: 5 - Production/Stable
6
6
  Classifier: Intended Audience :: Developers
@@ -26,6 +26,7 @@ tests/test_folders.py
26
26
  tests/test_iroh_webxdc.py
27
27
  tests/test_key_transfer.py
28
28
  tests/test_multidevice.py
29
+ tests/test_multitransport.py
29
30
  tests/test_securejoin.py
30
31
  tests/test_something.py
31
32
  tests/test_vcard.py
@@ -143,7 +143,7 @@ def test_delete_deltachat_folder(acfactory, direct_imap):
143
143
  # Wait until new folder is created and UIDVALIDITY is updated.
144
144
  while True:
145
145
  event = ac1.wait_for_event()
146
- if event.kind == EventType.INFO and "uid/validity change folder DeltaChat" in event.msg:
146
+ if event.kind == EventType.INFO and "transport 1: UID validity for folder DeltaChat changed from " in event.msg:
147
147
  break
148
148
 
149
149
  ac2 = acfactory.get_online_account()
@@ -0,0 +1,158 @@
1
+ import pytest
2
+
3
+ from deltachat_rpc_client.rpc import JsonRpcError
4
+
5
+
6
+ def test_add_second_address(acfactory) -> None:
7
+ account = acfactory.new_configured_account()
8
+ assert len(account.list_transports()) == 1
9
+
10
+ # When the first transport is created,
11
+ # mvbox_move and only_fetch_mvbox should be disabled.
12
+ assert account.get_config("mvbox_move") == "0"
13
+ assert account.get_config("only_fetch_mvbox") == "0"
14
+ assert account.get_config("show_emails") == "2"
15
+
16
+ qr = acfactory.get_account_qr()
17
+ account.add_transport_from_qr(qr)
18
+ assert len(account.list_transports()) == 2
19
+
20
+ account.add_transport_from_qr(qr)
21
+ assert len(account.list_transports()) == 3
22
+
23
+ first_addr = account.list_transports()[0]["addr"]
24
+ second_addr = account.list_transports()[1]["addr"]
25
+
26
+ # Cannot delete the first address.
27
+ with pytest.raises(JsonRpcError):
28
+ account.delete_transport(first_addr)
29
+
30
+ account.delete_transport(second_addr)
31
+ assert len(account.list_transports()) == 2
32
+
33
+ # Enabling mvbox_move or only_fetch_mvbox
34
+ # is not allowed when multi-transport is enabled.
35
+ for option in ["mvbox_move", "only_fetch_mvbox"]:
36
+ with pytest.raises(JsonRpcError):
37
+ account.set_config(option, "1")
38
+
39
+ with pytest.raises(JsonRpcError):
40
+ account.set_config("show_emails", "0")
41
+
42
+
43
+ @pytest.mark.parametrize("key", ["mvbox_move", "only_fetch_mvbox"])
44
+ def test_no_second_transport_with_mvbox(acfactory, key) -> None:
45
+ """Test that second transport cannot be configured if mvbox is used."""
46
+ account = acfactory.new_configured_account()
47
+ assert len(account.list_transports()) == 1
48
+
49
+ assert account.get_config("mvbox_move") == "0"
50
+ assert account.get_config("only_fetch_mvbox") == "0"
51
+
52
+ qr = acfactory.get_account_qr()
53
+ account.set_config(key, "1")
54
+
55
+ with pytest.raises(JsonRpcError):
56
+ account.add_transport_from_qr(qr)
57
+
58
+
59
+ def test_no_second_transport_without_classic_emails(acfactory) -> None:
60
+ """Test that second transport cannot be configured if classic emails are not fetched."""
61
+ account = acfactory.new_configured_account()
62
+ assert len(account.list_transports()) == 1
63
+
64
+ assert account.get_config("show_emails") == "2"
65
+
66
+ qr = acfactory.get_account_qr()
67
+ account.set_config("show_emails", "0")
68
+
69
+ with pytest.raises(JsonRpcError):
70
+ account.add_transport_from_qr(qr)
71
+
72
+
73
+ def test_change_address(acfactory) -> None:
74
+ """Test Alice configuring a second transport and setting it as a primary one."""
75
+ alice, bob = acfactory.get_online_accounts(2)
76
+
77
+ bob_addr = bob.get_config("configured_addr")
78
+ bob.create_chat(alice)
79
+
80
+ alice_chat_bob = alice.create_chat(bob)
81
+ alice_chat_bob.send_text("Hello!")
82
+
83
+ msg1 = bob.wait_for_incoming_msg().get_snapshot()
84
+ sender_addr1 = msg1.sender.get_snapshot().address
85
+
86
+ alice.stop_io()
87
+ old_alice_addr = alice.get_config("configured_addr")
88
+ alice_vcard = alice.self_contact.make_vcard()
89
+ assert old_alice_addr in alice_vcard
90
+ qr = acfactory.get_account_qr()
91
+ alice.add_transport_from_qr(qr)
92
+ new_alice_addr = alice.list_transports()[1]["addr"]
93
+ with pytest.raises(JsonRpcError):
94
+ # Cannot use the address that is not
95
+ # configured for any transport.
96
+ alice.set_config("configured_addr", bob_addr)
97
+
98
+ # Load old address so it is cached.
99
+ assert alice.get_config("configured_addr") == old_alice_addr
100
+ alice.set_config("configured_addr", new_alice_addr)
101
+ # Make sure that setting `configured_addr` invalidated the cache.
102
+ assert alice.get_config("configured_addr") == new_alice_addr
103
+
104
+ alice_vcard = alice.self_contact.make_vcard()
105
+ assert old_alice_addr not in alice_vcard
106
+ assert new_alice_addr in alice_vcard
107
+ with pytest.raises(JsonRpcError):
108
+ alice.delete_transport(new_alice_addr)
109
+ alice.start_io()
110
+
111
+ alice_chat_bob.send_text("Hello again!")
112
+
113
+ msg2 = bob.wait_for_incoming_msg().get_snapshot()
114
+ sender_addr2 = msg2.sender.get_snapshot().address
115
+
116
+ assert msg1.sender == msg2.sender
117
+ assert sender_addr1 != sender_addr2
118
+ assert sender_addr1 == old_alice_addr
119
+ assert sender_addr2 == new_alice_addr
120
+
121
+
122
+ @pytest.mark.parametrize("is_chatmail", ["0", "1"])
123
+ def test_mvbox_move_first_transport(acfactory, is_chatmail) -> None:
124
+ """Test that mvbox_move is disabled by default even for non-chatmail accounts.
125
+ Disabling mvbox_move is required to be able to setup a second transport.
126
+ """
127
+ account = acfactory.get_unconfigured_account()
128
+
129
+ account.set_config("fix_is_chatmail", "1")
130
+ account.set_config("is_chatmail", is_chatmail)
131
+
132
+ # The default value when the setting is unset is "1".
133
+ # This is not changed for compatibility with old databases
134
+ # imported from backups.
135
+ assert account.get_config("mvbox_move") == "1"
136
+
137
+ qr = acfactory.get_account_qr()
138
+ account.add_transport_from_qr(qr)
139
+
140
+ # Once the first transport is set up,
141
+ # mvbox_move is disabled.
142
+ assert account.get_config("mvbox_move") == "0"
143
+ assert account.get_config("is_chatmail") == is_chatmail
144
+
145
+
146
+ def test_reconfigure_transport(acfactory) -> None:
147
+ """Test that reconfiguring the transport works
148
+ even if settings not supported for multi-transport
149
+ like mvbox_move are enabled."""
150
+ account = acfactory.get_online_account()
151
+ account.set_config("mvbox_move", "1")
152
+
153
+ [transport] = account.list_transports()
154
+ account.add_or_update_transport(transport)
155
+
156
+ # Reconfiguring the transport should not reset
157
+ # the settings as if when configuring the first transport.
158
+ assert account.get_config("mvbox_move") == "1"
@@ -158,29 +158,29 @@ def test_qr_securejoin_broadcast(acfactory, all_devices_online):
158
158
  chat = get_broadcast(ac)
159
159
  chat_msgs = chat.get_messages()
160
160
 
161
+ encrypted_msg = chat_msgs.pop(0).get_snapshot()
162
+ assert encrypted_msg.text == "Messages are end-to-end encrypted."
163
+ assert encrypted_msg.is_info
164
+
161
165
  if please_wait_info_msg:
162
166
  first_msg = chat_msgs.pop(0).get_snapshot()
163
- assert first_msg.text == "Establishing guaranteed end-to-end encryption, please wait…"
167
+ assert "invited you to join this channel" in first_msg.text
164
168
  assert first_msg.is_info
165
169
 
166
- encrypted_msg = chat_msgs[0].get_snapshot()
167
- assert encrypted_msg.text == "Messages are end-to-end encrypted."
168
- assert encrypted_msg.is_info
169
-
170
- member_added_msg = chat_msgs[1].get_snapshot()
170
+ member_added_msg = chat_msgs.pop(0).get_snapshot()
171
171
  if inviter_side:
172
172
  assert member_added_msg.text == f"Member {contact_snapshot.display_name} added."
173
173
  else:
174
174
  assert member_added_msg.text == "You joined the channel."
175
175
  assert member_added_msg.is_info
176
176
 
177
- hello_msg = chat_msgs[2].get_snapshot()
177
+ hello_msg = chat_msgs.pop(0).get_snapshot()
178
178
  assert hello_msg.text == "Hello everyone!"
179
179
  assert not hello_msg.is_info
180
180
  assert hello_msg.show_padlock
181
181
  assert hello_msg.error is None
182
182
 
183
- assert len(chat_msgs) == 3
183
+ assert len(chat_msgs) == 0
184
184
 
185
185
  chat_snapshot = chat.get_full_snapshot()
186
186
  assert chat_snapshot.is_encrypted
@@ -467,7 +467,7 @@ def test_bot(acfactory) -> None:
467
467
 
468
468
 
469
469
  def test_wait_next_messages(acfactory) -> None:
470
- alice = acfactory.new_configured_account()
470
+ alice = acfactory.get_online_account()
471
471
 
472
472
  # Create a bot account so it does not receive device messages in the beginning.
473
473
  addr, password = acfactory.get_credentials()
@@ -475,6 +475,7 @@ def test_wait_next_messages(acfactory) -> None:
475
475
  bot.set_config("bot", "1")
476
476
  bot.add_or_update_transport({"addr": addr, "password": password})
477
477
  assert bot.is_configured()
478
+ bot.bring_online()
478
479
 
479
480
  # There are no old messages and the call returns immediately.
480
481
  assert not bot.wait_next_messages()
@@ -867,15 +868,15 @@ def test_leave_broadcast(acfactory, all_devices_online):
867
868
  contact_snapshot = contact.get_snapshot()
868
869
  chat_msgs = chat.get_messages()
869
870
 
870
- if please_wait_info_msg:
871
- first_msg = chat_msgs.pop(0).get_snapshot()
872
- assert first_msg.text == "Establishing guaranteed end-to-end encryption, please wait…"
873
- assert first_msg.is_info
874
-
875
871
  encrypted_msg = chat_msgs.pop(0).get_snapshot()
876
872
  assert encrypted_msg.text == "Messages are end-to-end encrypted."
877
873
  assert encrypted_msg.is_info
878
874
 
875
+ if please_wait_info_msg:
876
+ first_msg = chat_msgs.pop(0).get_snapshot()
877
+ assert "invited you to join this channel" in first_msg.text
878
+ assert first_msg.is_info
879
+
879
880
  member_added_msg = chat_msgs.pop(0).get_snapshot()
880
881
  if inviter_side:
881
882
  assert member_added_msg.text == f"Member {contact_snapshot.display_name} added."