deltachat-rpc-client 1.157.2__py3-none-any.whl → 1.158.0__py3-none-any.whl

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,8 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from pathlib import Path
5
- from tempfile import TemporaryDirectory
6
4
  from typing import TYPE_CHECKING, Optional, Union
7
5
  from warnings import warn
8
6
 
@@ -28,9 +26,12 @@ class Account:
28
26
  def _rpc(self) -> "Rpc":
29
27
  return self.manager.rpc
30
28
 
31
- def wait_for_event(self) -> AttrDict:
29
+ def wait_for_event(self, event_type=None) -> AttrDict:
32
30
  """Wait until the next event and return it."""
33
- return AttrDict(self._rpc.wait_for_event(self.id))
31
+ while True:
32
+ next_event = AttrDict(self._rpc.wait_for_event(self.id))
33
+ if event_type is None or next_event.kind == event_type:
34
+ return next_event
34
35
 
35
36
  def clear_all_events(self):
36
37
  """Removes all queued-up events for a given account. Useful for tests."""
@@ -41,14 +42,14 @@ class Account:
41
42
  self._rpc.remove_account(self.id)
42
43
 
43
44
  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
45
+ """Clone given account.
46
+ This uses backup-transfer via iroh, i.e. the 'Add second device' feature."""
47
+ future = self._rpc.provide_backup.future(self.id)
48
+ qr = self._rpc.get_backup_qr(self.id)
49
+ new_account = self.manager.add_account()
50
+ new_account._rpc.get_backup(new_account.id, qr)
51
+ future()
52
+ return new_account
52
53
 
53
54
  def start_io(self) -> None:
54
55
  """Start the account I/O."""
@@ -112,12 +113,9 @@ class Account:
112
113
  def bring_online(self):
113
114
  """Start I/O and wait until IMAP becomes IDLE."""
114
115
  self.start_io()
115
- while True:
116
- event = self.wait_for_event()
117
- if event.kind == EventType.IMAP_INBOX_IDLE:
118
- break
116
+ self.wait_for_event(EventType.IMAP_INBOX_IDLE)
119
117
 
120
- def create_contact(self, obj: Union[int, str, Contact], name: Optional[str] = None) -> Contact:
118
+ def create_contact(self, obj: Union[int, str, Contact, "Account"], name: Optional[str] = None) -> Contact:
121
119
  """Create a new Contact or return an existing one.
122
120
 
123
121
  Calling this method will always result in the same
@@ -125,9 +123,15 @@ class Account:
125
123
  with that e-mail address, it is unblocked and its display
126
124
  name is updated if specified.
127
125
 
128
- :param obj: email-address or contact id.
126
+ :param obj: email-address, contact id or account.
129
127
  :param name: (optional) display name for this contact.
130
128
  """
129
+ if isinstance(obj, Account):
130
+ vcard = obj.self_contact.make_vcard()
131
+ [contact] = self.import_vcard(vcard)
132
+ if name:
133
+ contact.set_name(name)
134
+ return contact
131
135
  if isinstance(obj, int):
132
136
  obj = Contact(self, obj)
133
137
  if isinstance(obj, Contact):
@@ -148,9 +152,8 @@ class Account:
148
152
  return [Contact(self, contact_id) for contact_id in contact_ids]
149
153
 
150
154
  def create_chat(self, account: "Account") -> Chat:
151
- vcard = account.self_contact.make_vcard()
152
- [contact] = self.import_vcard(vcard)
153
- return contact.create_chat()
155
+ """Create a 1:1 chat with another account."""
156
+ return self.create_contact(account).create_chat()
154
157
 
155
158
  def get_device_chat(self) -> Chat:
156
159
  """Return device chat."""
@@ -334,24 +337,15 @@ class Account:
334
337
 
335
338
  def wait_for_incoming_msg_event(self):
336
339
  """Wait for incoming message event and return it."""
337
- while True:
338
- event = self.wait_for_event()
339
- if event.kind == EventType.INCOMING_MSG:
340
- return event
340
+ return self.wait_for_event(EventType.INCOMING_MSG)
341
341
 
342
342
  def wait_for_msgs_changed_event(self):
343
343
  """Wait for messages changed event and return it."""
344
- while True:
345
- event = self.wait_for_event()
346
- if event.kind == EventType.MSGS_CHANGED:
347
- return event
344
+ return self.wait_for_event(EventType.MSGS_CHANGED)
348
345
 
349
346
  def wait_for_msgs_noticed_event(self):
350
347
  """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
348
+ return self.wait_for_event(EventType.MSGS_NOTICED)
355
349
 
356
350
  def wait_for_incoming_msg(self):
357
351
  """Wait for incoming message and return it.
@@ -372,10 +366,7 @@ class Account:
372
366
  break
373
367
 
374
368
  def wait_for_reactions_changed(self):
375
- while True:
376
- event = self.wait_for_event()
377
- if event.kind == EventType.REACTIONS_CHANGED:
378
- return event
369
+ return self.wait_for_event(EventType.REACTIONS_CHANGED)
379
370
 
380
371
  def get_fresh_messages_in_arrival_order(self) -> list[Message]:
381
372
  """Return fresh messages list sorted in the order of their arrival, with ascending IDs."""
@@ -4,6 +4,7 @@ import os
4
4
  import random
5
5
  from typing import AsyncGenerator, Optional
6
6
 
7
+ import py
7
8
  import pytest
8
9
 
9
10
  from . import Account, AttrDict, Bot, Chat, Client, DeltaChat, EventType, Message
@@ -11,14 +12,6 @@ from ._utils import futuremethod
11
12
  from .rpc import Rpc
12
13
 
13
14
 
14
- def get_temp_credentials() -> dict:
15
- domain = os.getenv("CHATMAIL_DOMAIN")
16
- username = "ci-" + "".join(random.choice("2345789acdefghjkmnpqrstuvwxyz") for i in range(6))
17
- password = f"{username}${username}"
18
- addr = f"{username}@{domain}"
19
- return {"email": addr, "password": password}
20
-
21
-
22
15
  class ACFactory:
23
16
  def __init__(self, deltachat: DeltaChat) -> None:
24
17
  self.deltachat = deltachat
@@ -31,26 +24,25 @@ class ACFactory:
31
24
  def get_unconfigured_bot(self) -> Bot:
32
25
  return Bot(self.get_unconfigured_account())
33
26
 
34
- def new_preconfigured_account(self) -> Account:
35
- """Make a new account with configuration options set, but configuration not started."""
36
- credentials = get_temp_credentials()
37
- account = self.get_unconfigured_account()
38
- account.set_config("addr", credentials["email"])
39
- account.set_config("mail_pw", credentials["password"])
40
- assert not account.is_configured()
41
- return account
27
+ def get_credentials(self) -> (str, str):
28
+ domain = os.getenv("CHATMAIL_DOMAIN")
29
+ username = "ci-" + "".join(random.choice("2345789acdefghjkmnpqrstuvwxyz") for i in range(6))
30
+ return f"{username}@{domain}", f"{username}${username}"
42
31
 
43
32
  @futuremethod
44
33
  def new_configured_account(self):
45
- account = self.new_preconfigured_account()
46
- yield account.configure.future()
34
+ addr, password = self.get_credentials()
35
+ account = self.get_unconfigured_account()
36
+ params = {"addr": addr, "password": password}
37
+ yield account._rpc.add_transport.future(account.id, params)
38
+
47
39
  assert account.is_configured()
48
40
  return account
49
41
 
50
42
  def new_configured_bot(self) -> Bot:
51
- credentials = get_temp_credentials()
43
+ addr, password = self.get_credentials()
52
44
  bot = self.get_unconfigured_bot()
53
- bot.configure(credentials["email"], credentials["password"])
45
+ bot.configure(addr, password)
54
46
  return bot
55
47
 
56
48
  @futuremethod
@@ -124,3 +116,50 @@ def rpc(tmp_path) -> AsyncGenerator:
124
116
  @pytest.fixture
125
117
  def acfactory(rpc) -> AsyncGenerator:
126
118
  return ACFactory(DeltaChat(rpc))
119
+
120
+
121
+ @pytest.fixture
122
+ def data():
123
+ """Test data."""
124
+
125
+ class Data:
126
+ def __init__(self) -> None:
127
+ for path in reversed(py.path.local(__file__).parts()):
128
+ datadir = path.join("test-data")
129
+ if datadir.isdir():
130
+ self.path = datadir
131
+ return
132
+ raise Exception("Data path cannot be found")
133
+
134
+ def get_path(self, bn):
135
+ """return path of file or None if it doesn't exist."""
136
+ fn = os.path.join(self.path, *bn.split("/"))
137
+ assert os.path.exists(fn)
138
+ return fn
139
+
140
+ def read_path(self, bn, mode="r"):
141
+ fn = self.get_path(bn)
142
+ if fn is not None:
143
+ with open(fn, mode) as f:
144
+ return f.read()
145
+ return None
146
+
147
+ return Data()
148
+
149
+
150
+ @pytest.fixture
151
+ def log():
152
+ """Log printer fixture."""
153
+
154
+ class Printer:
155
+ def section(self, msg: str) -> None:
156
+ print()
157
+ print("=" * 10, msg, "=" * 10)
158
+
159
+ def step(self, msg: str) -> None:
160
+ print("-" * 5, "step " + msg, "-" * 5)
161
+
162
+ def indent(self, msg: str) -> None:
163
+ print(" " + msg)
164
+
165
+ return Printer()
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: deltachat-rpc-client
3
- Version: 1.157.2
3
+ Version: 1.158.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
@@ -19,6 +19,7 @@ Classifier: Topic :: Communications :: Email
19
19
  Requires-Python: >=3.8
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
+ Dynamic: license-file
22
23
 
23
24
  # Delta Chat RPC python client
24
25
 
@@ -1,6 +1,6 @@
1
1
  deltachat_rpc_client/__init__.py,sha256=L19BWnRu9TMF--jQ7e5Asgme951WGsldrTknW86KyTg,566
2
2
  deltachat_rpc_client/_utils.py,sha256=pLOV_pxS2MRreLtq-5rnKJp-BP0m8T4LcbJ8N7Xy-D0,6304
3
- deltachat_rpc_client/account.py,sha256=FGZrM-BdnL6h7P9h1F_svVwYXF94uCm2JmtdjnPR4Lc,15886
3
+ deltachat_rpc_client/account.py,sha256=P4R_DMsVdyWu3qj4q2orwDa273Pg5Z16yivssPU6Eu4,15798
4
4
  deltachat_rpc_client/chat.py,sha256=1pbuEBWBjZDD9qQ3U1hY5jozzx0MSs9Ybpw33reA2MU,11208
5
5
  deltachat_rpc_client/client.py,sha256=yyXt2USkBeTsqNxtXZNNUqdsPVkqEUHYf7C-5JFmX7s,7043
6
6
  deltachat_rpc_client/const.py,sha256=geXY_H-JHn2HLsYPAAWbwnX5LOksU7zqDZh3AOwmUpg,5577
@@ -9,11 +9,11 @@ deltachat_rpc_client/deltachat.py,sha256=c22_2GX71we6JwQ4yjP-S89mrUYPPbEb3rrPwHH
9
9
  deltachat_rpc_client/events.py,sha256=qYgydsbuWYxQ1PO5ms-D8I5aHpTIiQ6Fg9p23QTvqf0,9877
10
10
  deltachat_rpc_client/message.py,sha256=LVgQTzgaTS-24NPqSLYjgCtyz9PiTPWQgO0c_j9tIs4,3021
11
11
  deltachat_rpc_client/py.typed,sha256=nGQ9Itq-bkXBn5Ri1JIR0oYnDNv7LDRfkowxBSSqVTM,60
12
- deltachat_rpc_client/pytestplugin.py,sha256=zRRxsSBvzpbRUxSmKjd7EKZbosAb60Ew53Yu5W7W4Nc,4055
12
+ deltachat_rpc_client/pytestplugin.py,sha256=c1KSv6mc2UGzmfgr8C6_7-6WqTdE97S9QDhuukLv02Y,4900
13
13
  deltachat_rpc_client/rpc.py,sha256=7RIdyEDwOXU0ACU0LanVqTT1RuIDci5iDr7dNEDE_tE,6554
14
- deltachat_rpc_client-1.157.2.dist-info/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
15
- deltachat_rpc_client-1.157.2.dist-info/METADATA,sha256=NbcIShQYhVfPviabg3eQf2HXeSYTwbGD3QkI2Iz1hwQ,2153
16
- deltachat_rpc_client-1.157.2.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
17
- deltachat_rpc_client-1.157.2.dist-info/entry_points.txt,sha256=VHpX6EnKBaNj89qJWctApThnMa8suyaamfZEnQacXgc,81
18
- deltachat_rpc_client-1.157.2.dist-info/top_level.txt,sha256=ePNMkY10htGrLiLydH1ITvYFM3LcTEa51HyPqJ40hDk,21
19
- deltachat_rpc_client-1.157.2.dist-info/RECORD,,
14
+ deltachat_rpc_client-1.158.0.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
15
+ deltachat_rpc_client-1.158.0.dist-info/METADATA,sha256=5L0z-yQbsvJkMpuc56GD3a2y28aYpXUSggVA9pyLWMo,2175
16
+ deltachat_rpc_client-1.158.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
17
+ deltachat_rpc_client-1.158.0.dist-info/entry_points.txt,sha256=VHpX6EnKBaNj89qJWctApThnMa8suyaamfZEnQacXgc,81
18
+ deltachat_rpc_client-1.158.0.dist-info/top_level.txt,sha256=ePNMkY10htGrLiLydH1ITvYFM3LcTEa51HyPqJ40hDk,21
19
+ deltachat_rpc_client-1.158.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.0.0)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5