deltabot-cli 7.2.0__tar.gz → 8.1.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.
@@ -13,33 +13,27 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  strategy:
15
15
  matrix:
16
- python-version: ['3.9', '3.11']
16
+ python-version: ['3.10', '3.13']
17
17
  steps:
18
- - uses: actions/checkout@v2
19
- - name: Set up Python ${{ matrix.python-version }}
20
- uses: actions/setup-python@v2
21
- with:
22
- python-version: ${{ matrix.python-version }}
23
- - name: Install dependencies
24
- run: |
25
- python -m pip install --upgrade pip
26
- python -m pip install '.[dev]'
27
- - name: Check code with black
28
- run: |
29
- black --check .
30
- - name: Lint code
31
- run: |
32
- pylama
33
- - name: Test with pytest
34
- run: |
35
- #pytest
18
+ - uses: actions/checkout@v6
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v6
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ - name: Install dependencies
24
+ run: |
25
+ python -m pip install --upgrade pip
26
+ python -m pip install '.[dev]'
27
+ - run: isort --check .
28
+ - run: black --check .
29
+ - run: prospector
36
30
 
37
31
  deploy:
38
32
  needs: test
39
33
  runs-on: ubuntu-latest
40
34
  steps:
41
- - uses: actions/checkout@v2
42
- - uses: actions/setup-python@v2
35
+ - uses: actions/checkout@v6
36
+ - uses: actions/setup-python@v6
43
37
  with:
44
38
  python-version: '3.x'
45
39
  - id: check-tag
@@ -1,3 +1,4 @@
1
+ venv
1
2
  __pycache__
2
3
  .cache
3
4
  .mypy_cache
@@ -0,0 +1,16 @@
1
+ strictness: medium
2
+ test-warnings: true
3
+ doc-warnings: false
4
+
5
+ ignore-paths:
6
+ - docs
7
+ - build
8
+
9
+ ignore-patterns:
10
+ - (^|/)skip(this)?(/|$)
11
+
12
+ mccabe:
13
+ run: false
14
+
15
+ mypy:
16
+ run: true
@@ -1,27 +1,24 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deltabot-cli
3
- Version: 7.2.0
3
+ Version: 8.1.0
4
4
  Summary: Library to speedup Delta Chat bot development
5
- Author-email: adbenitez <adb@merlinux.eu>
5
+ Author-email: adbenitez <adb@arcanechat.me>
6
6
  Project-URL: Homepage, https://github.com/deltachat-bot/deltabot-cli-py
7
7
  Keywords: deltachat,bot,deltabot-cli
8
8
  Classifier: Development Status :: 4 - Beta
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
12
- Requires-Python: >=3.8
12
+ Requires-Python: >=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: deltachat2[full]>=0.8.0
15
+ Requires-Dist: deltachat2[full]>=0.10.0
16
16
  Requires-Dist: appdirs>=1.4.4
17
17
  Requires-Dist: rich>=12.6.0
18
18
  Provides-Extra: dev
19
19
  Requires-Dist: black; extra == "dev"
20
- Requires-Dist: mypy; extra == "dev"
21
20
  Requires-Dist: isort; extra == "dev"
22
- Requires-Dist: pylint; extra == "dev"
23
- Requires-Dist: pylama; extra == "dev"
24
- Requires-Dist: pytest; extra == "dev"
21
+ Requires-Dist: prospector[with-mypy]; extra == "dev"
25
22
  Dynamic: license-file
26
23
 
27
24
  # deltabot-cli for Python
@@ -1,4 +1,3 @@
1
1
  """Library to help with Delta Chat bot development"""
2
2
 
3
- # pylama:ignore=W0611
4
- from .cli import BotCli
3
+ from .cli import BotCli # noqa
@@ -8,7 +8,7 @@ import time
8
8
  from argparse import ArgumentParser, Namespace
9
9
  from pathlib import Path
10
10
  from threading import Thread
11
- from typing import Callable, Set, Union
11
+ from typing import Callable, Union
12
12
 
13
13
  from appdirs import user_config_dir
14
14
  from deltachat2 import Bot, CoreEvent, Event, EventType, IOTransport, JsonRpcError, Rpc
@@ -32,11 +32,12 @@ class BotCli:
32
32
  def __init__(self, app_name: str, log_level: str = "info") -> None:
33
33
  self.app_name = app_name
34
34
  self.log_level = log_level
35
+ self._base_parser = ArgumentParser(add_help=False)
35
36
  self._parser = ArgumentParser(app_name)
36
37
  self._subparsers = self._parser.add_subparsers(title="subcommands")
37
38
  self._hooks = HookCollection()
38
- self._init_hooks: Set[CliEventHook] = set()
39
- self._start_hooks: Set[CliEventHook] = set()
39
+ self._init_hooks: set[CliEventHook] = set()
40
+ self._start_hooks: set[CliEventHook] = set()
40
41
  self._bot: Bot
41
42
 
42
43
  def on(self, event: Union[type, EventFilter]) -> HookDecorator:
@@ -72,9 +73,14 @@ class BotCli:
72
73
  func(bot, args)
73
74
 
74
75
  def add_generic_option(self, *flags, **kwargs) -> None:
75
- """Add a generic argument option to the CLI."""
76
+ """Add a generic argument option to the CLI.
77
+
78
+ For the generic option to be usable also after a subcommand,
79
+ it must be registered before any subcommand.
80
+ """
76
81
  if not (flags and flags[0].startswith("-")):
77
82
  raise ValueError("can not generically add positional args")
83
+ self._base_parser.add_argument(*flags, **kwargs)
78
84
  self._parser.add_argument(*flags, **kwargs)
79
85
 
80
86
  def add_subcommand(
@@ -87,6 +93,8 @@ class BotCli:
87
93
  kwargs["name"] = func.__name__
88
94
  if not kwargs.get("help") and not kwargs.get("description"):
89
95
  kwargs["help"], kwargs["description"] = parse_docstring(func.__doc__)
96
+ if "parents" not in kwargs:
97
+ kwargs["parents"] = [self._base_parser]
90
98
  subparser = self._subparsers.add_parser(**kwargs)
91
99
  subparser.set_defaults(cmd=func)
92
100
  return subparser
@@ -108,8 +116,9 @@ class BotCli:
108
116
  self.add_generic_option(
109
117
  "--account",
110
118
  "-a",
111
- help="operate only over the given account when running any subcommand",
112
- metavar="ADDR",
119
+ help="operate only over the profile with the given ID when running any subcommand",
120
+ metavar="ID",
121
+ type=int,
113
122
  )
114
123
  choices = ["debug", "info", "warning", "error"]
115
124
  assert (
@@ -124,8 +133,15 @@ class BotCli:
124
133
  )
125
134
 
126
135
  init_parser = self.add_subcommand(_init_cmd, name="init")
127
- init_parser.add_argument("addr", help="the e-mail address to use")
128
- init_parser.add_argument("password", help="account password")
136
+ init_parser.add_argument(
137
+ "addr",
138
+ help=("the e-mail address to use or a DCACCOUNT URI ex. DCACCOUNT:nine.testrun.org"),
139
+ )
140
+ init_parser.add_argument(
141
+ "password",
142
+ nargs="?",
143
+ help="account password, this field is required only if addr is not a DCACCOUNT URI",
144
+ )
129
145
 
130
146
  config_parser = self.add_subcommand(_config_cmd, name="config")
131
147
  config_parser.add_argument("option", help="option name", nargs="?")
@@ -134,11 +150,25 @@ class BotCli:
134
150
  import_parser = self.add_subcommand(_import_cmd, name="import")
135
151
  import_parser.add_argument("path", help="path to the account backup", type=Path)
136
152
 
153
+ export_parser = self.add_subcommand(_export_cmd, name="export")
154
+ export_parser.add_argument(
155
+ "folder",
156
+ help="folder where the backup will be exported to",
157
+ type=Path,
158
+ default=Path(),
159
+ nargs="?",
160
+ )
161
+
137
162
  self.add_subcommand(_serve_cmd, name="serve")
138
163
  self.add_subcommand(_link_cmd, name="link")
139
164
  self.add_subcommand(_admin_cmd, name="admin")
140
165
  self.add_subcommand(_list_cmd, name="list")
141
- self.add_subcommand(_remove_cmd, name="remove")
166
+ remove_parser = self.add_subcommand(_remove_cmd, name="remove")
167
+ remove_parser.add_argument(
168
+ "address",
169
+ help="address to remove, if not provided the whole account is removed",
170
+ nargs="?",
171
+ )
142
172
 
143
173
  def get_accounts_dir(self, args: Namespace) -> str:
144
174
  """Get bot's account folder."""
@@ -146,32 +176,6 @@ class BotCli:
146
176
  os.makedirs(args.config_dir)
147
177
  return os.path.join(args.config_dir, "accounts")
148
178
 
149
- def get_or_create_account(self, rpc: Rpc, addr: str) -> int:
150
- """Get account for address, if no account exists create a new one."""
151
- accid = self.get_account(rpc, addr)
152
- if not accid:
153
- accid = rpc.add_account()
154
- rpc.set_config(accid, "addr", addr)
155
- return accid
156
-
157
- def get_account(self, rpc: Rpc, addr: str) -> int:
158
- """Get account id for address.
159
- If no account exists with the given address, zero is returned.
160
- """
161
- try:
162
- return int(addr)
163
- except ValueError:
164
- for accid in rpc.get_all_account_ids():
165
- if addr == self.get_address(rpc, accid):
166
- return accid
167
-
168
- return 0
169
-
170
- def get_address(self, rpc: Rpc, accid: int) -> str:
171
- if rpc.is_configured(accid):
172
- return rpc.get_config(accid, "configured_addr")
173
- return rpc.get_config(accid, "addr")
174
-
175
179
  def is_admin(self, rpc: Rpc, accid: int, contactid: int) -> bool:
176
180
  """Return True if the contact is an administrator.
177
181
  Administrators are the members of the Administration group.
@@ -190,7 +194,12 @@ class BotCli:
190
194
  if not rpc.is_configured(accid):
191
195
  return 0
192
196
  chatid = int(rpc.get_config(accid, "ui.admin_chat") or 0)
193
- return chatid or self.reset_admin_chat(rpc, accid)
197
+ try:
198
+ if rpc.can_send(accid, chatid):
199
+ return chatid
200
+ except JsonRpcError:
201
+ pass
202
+ return self.reset_admin_chat(rpc, accid)
194
203
 
195
204
  def reset_admin_chat(self, rpc: Rpc, accid: int) -> int:
196
205
  """Reset the bot administration group and return the new group id.
@@ -225,40 +234,58 @@ class BotCli:
225
234
  self._parser.parse_args(["-h"])
226
235
 
227
236
 
228
- def _init_cmd(cli: BotCli, bot: Bot, args: Namespace) -> None: # noqa: C901
237
+ def _ensure_one_acc(bot: Bot, args: Namespace) -> int:
238
+ if args.account:
239
+ accounts = [args.account]
240
+ else:
241
+ accounts = bot.rpc.get_all_account_ids()
242
+
243
+ if len(accounts) == 1:
244
+ return accounts[0]
245
+ bot.logger.error(
246
+ "There is more than one account, please provide an account id with -a/--account option"
247
+ )
248
+ sys.exit(1)
249
+
250
+
251
+ def _init_cmd(_cli: BotCli, bot: Bot, args: Namespace) -> None:
229
252
  """initialize the account"""
230
253
 
231
- def configure() -> None:
232
- try:
233
- bot.configure(accid, email=args.addr, password=args.password)
234
- except JsonRpcError as err:
235
- bot.logger.error(err)
254
+ def process_events() -> None:
255
+ events = (EventType.INFO, EventType.WARNING, EventType.ERROR)
256
+ while True:
257
+ raw_event = bot.rpc.get_next_event()
258
+ accid = raw_event.context_id
259
+ event = CoreEvent(raw_event.event)
260
+ if event.kind == EventType.CONFIGURE_PROGRESS:
261
+ if event.comment:
262
+ bot.logger.info(event.comment)
263
+ pbar.set_progress(event.progress)
264
+ elif event.kind in events:
265
+ bot._on_event(Event(accid, event), RawEvent) # noqa
266
+ if pbar.progress in (-1, pbar.total):
267
+ break
236
268
 
237
269
  if args.account:
238
- accid = cli.get_account(bot.rpc, args.account)
239
- if not accid:
240
- bot.logger.error(f"unknown account: {args.account!r}")
241
- sys.exit(1)
270
+ accid = args.account
242
271
  else:
243
- accid = cli.get_or_create_account(bot.rpc, args.addr)
272
+ accid = bot.rpc.add_account()
244
273
 
245
274
  bot.logger.info("Starting configuration process...")
246
- task = Thread(target=configure, daemon=True)
247
- task.start()
275
+ bot.rpc.set_config(accid, "bot", "1")
248
276
  pbar = ConfigProgressBar()
249
- while True:
250
- raw_event = bot.rpc.get_next_event()
251
- accid = raw_event.context_id
252
- event = CoreEvent(raw_event.event)
253
- if event.kind == EventType.CONFIGURE_PROGRESS:
254
- if event.comment:
255
- bot.logger.info(event.comment)
256
- pbar.set_progress(event.progress)
257
- elif event.kind in (EventType.INFO, EventType.WARNING, EventType.ERROR):
258
- bot._on_event(Event(accid, event), RawEvent) # noqa: access to protected field
259
- if pbar.progress in (-1, pbar.total):
260
- break
261
- task.join()
277
+ task = Thread(target=process_events, daemon=True)
278
+ task.start()
279
+ try:
280
+ if not args.password:
281
+ bot.rpc.add_transport_from_qr(accid, args.addr)
282
+ else:
283
+ params = {"addr": args.addr, "password": args.password}
284
+ bot.rpc.add_or_update_transport(accid, params)
285
+ task.join()
286
+ except JsonRpcError as err:
287
+ bot.logger.error(err)
288
+ pbar.progress = -1
262
289
  pbar.close()
263
290
  if pbar.progress == -1:
264
291
  bot.logger.error("Configuration failed.")
@@ -271,27 +298,25 @@ def _serve_cmd(cli: BotCli, bot: Bot, args: Namespace) -> None:
271
298
  """start processing messages"""
272
299
  rpc = bot.rpc
273
300
  if args.account:
274
- accounts = [cli.get_account(rpc, args.account)]
275
- if not accounts[0]:
276
- bot.logger.error(f"unknown account: {args.account!r}")
277
- sys.exit(1)
301
+ accounts = [args.account]
278
302
  else:
279
303
  accounts = rpc.get_all_account_ids()
280
- addrs = []
304
+ configured = False
281
305
  for accid in accounts:
282
- if rpc.is_configured(accid):
283
- addrs.append(rpc.get_config(accid, "configured_addr"))
306
+ if bot.rpc.is_configured(accid):
307
+ configured = True
308
+ link = bot.rpc.get_chat_securejoin_qr_code(accid, None)
309
+ bot.logger.info(f"Listening at: {link}")
284
310
  else:
285
311
  bot.logger.error(f"account {accid} not configured")
286
- if len(addrs) != 0:
287
- bot.logger.info(f"Listening at: {', '.join(addrs)}")
312
+ if configured:
288
313
  cli._on_start(bot, args) # noqa
289
314
  while True:
290
315
  try:
291
316
  bot.run_forever(accounts[0] if args.account else 0)
292
317
  except KeyboardInterrupt:
293
318
  return
294
- except Exception as ex: # pylint:disable=W0703
319
+ except Exception as ex:
295
320
  bot.logger.exception(ex)
296
321
  time.sleep(5)
297
322
  else:
@@ -299,18 +324,14 @@ def _serve_cmd(cli: BotCli, bot: Bot, args: Namespace) -> None:
299
324
  sys.exit(1)
300
325
 
301
326
 
302
- def _config_cmd(cli: BotCli, bot: Bot, args: Namespace) -> None:
327
+ def _config_cmd(_cli: BotCli, bot: Bot, args: Namespace) -> None:
303
328
  """set/get account configuration values"""
304
329
  if args.account:
305
- accounts = [cli.get_account(bot.rpc, args.account)]
306
- if not accounts[0]:
307
- bot.logger.error(f"unknown account: {args.account!r}")
308
- sys.exit(1)
330
+ accounts = [args.account]
309
331
  else:
310
332
  accounts = bot.rpc.get_all_account_ids()
311
333
  for accid in accounts:
312
- addr = cli.get_address(bot.rpc, accid)
313
- print(f"Account #{accid} ({addr}):")
334
+ print(f"Account #{accid}:")
314
335
  _config_cmd_for_acc(bot, accid, args)
315
336
  print("")
316
337
  if not accounts:
@@ -339,15 +360,11 @@ def _admin_cmd(cli: BotCli, bot: Bot, args: Namespace) -> None:
339
360
  """print the invitation link to the bot administration group.
340
361
  WARNING: don't share this, anyone joining will become admin of the bot"""
341
362
  if args.account:
342
- accounts = [cli.get_account(bot.rpc, args.account)]
343
- if not accounts[0]:
344
- bot.logger.error(f"unknown account: {args.account!r}")
345
- sys.exit(1)
363
+ accounts = [args.account]
346
364
  else:
347
365
  accounts = bot.rpc.get_all_account_ids()
348
366
  for accid in accounts:
349
- addr = cli.get_address(bot.rpc, accid)
350
- print(f"Account #{accid} ({addr}):")
367
+ print(f"Account #{accid}:")
351
368
  _admin_cmd_for_acc(cli, bot, accid)
352
369
  print("")
353
370
  if not accounts:
@@ -365,18 +382,14 @@ def _admin_cmd_for_acc(cli: BotCli, bot: Bot, accid: int) -> None:
365
382
  bot.logger.error("account not configured")
366
383
 
367
384
 
368
- def _link_cmd(cli: BotCli, bot: Bot, args: Namespace) -> None:
385
+ def _link_cmd(_cli: BotCli, bot: Bot, args: Namespace) -> None:
369
386
  """print the bot's chat invitation link"""
370
387
  if args.account:
371
- accounts = [cli.get_account(bot.rpc, args.account)]
372
- if not accounts[0]:
373
- bot.logger.error(f"unknown account: {args.account!r}")
374
- sys.exit(1)
388
+ accounts = [args.account]
375
389
  else:
376
390
  accounts = bot.rpc.get_all_account_ids()
377
391
  for accid in accounts:
378
- addr = cli.get_address(bot.rpc, accid)
379
- print(f"Account #{accid} ({addr}):")
392
+ print(f"Account #{accid}:")
380
393
  _link_cmd_for_acc(bot, accid)
381
394
  print("")
382
395
  if not accounts:
@@ -393,38 +406,27 @@ def _link_cmd_for_acc(bot: Bot, accid: int) -> None:
393
406
  bot.logger.error("account not configured")
394
407
 
395
408
 
396
- def _list_cmd(cli: BotCli, bot: Bot, _args: Namespace) -> None:
409
+ def _list_cmd(_cli: BotCli, bot: Bot, _args: Namespace) -> None:
397
410
  """show a list of existing bot accounts"""
398
411
  rpc = bot.rpc
399
412
  accounts = rpc.get_all_account_ids()
400
413
  for accid in accounts:
401
- addr = cli.get_address(rpc, accid)
402
- if not rpc.is_configured(accid):
403
- addr = f"{addr or ''} (not configured)"
404
- print(f"#{accid} - {addr}")
414
+ transports = bot.rpc.list_transports(accid)
415
+ addrs = [params["addr"] for params in transports]
416
+ info = ", ".join(addrs) or "(not configured)"
417
+ print(f"#{accid} - {info}")
405
418
 
406
419
 
407
- def _remove_cmd(cli: BotCli, bot: Bot, args: Namespace) -> None:
420
+ def _remove_cmd(_cli: BotCli, bot: Bot, args: Namespace) -> None:
408
421
  """remove Delta Chat accounts from the bot"""
409
- if args.account:
410
- accid = cli.get_account(bot.rpc, args.account)
411
- if not accid:
412
- bot.logger.error(f"unknown account: {args.account!r}")
413
- sys.exit(1)
414
- else:
415
- accounts = bot.rpc.get_all_account_ids()
416
- if len(accounts) == 1:
417
- accid = accounts[0]
418
- else:
419
- bot.logger.error(
420
- "There are more than one account, to remove one of them, pass the account"
421
- " address with -a/--account option"
422
- )
423
- sys.exit(1)
422
+ accid = _ensure_one_acc(bot, args)
424
423
 
425
- addr = cli.get_address(bot.rpc, accid)
426
- bot.rpc.remove_account(accid)
427
- print(f"Account #{accid} ({addr}) removed successfully.")
424
+ if args.address:
425
+ bot.rpc.delete_transport(accid, args.address)
426
+ print(f"Account #{accid}: removed address {args.address}")
427
+ else:
428
+ bot.rpc.remove_account(accid)
429
+ print(f"Account #{accid} removed successfully.")
428
430
 
429
431
 
430
432
  def _import_cmd(_cli: BotCli, bot: Bot, args: Namespace) -> None:
@@ -440,5 +442,21 @@ def _import_cmd(_cli: BotCli, bot: Bot, args: Namespace) -> None:
440
442
  bot.logger.exception(ex)
441
443
  sys.exit(1)
442
444
  else:
443
- addr = bot.rpc.get_config(accid, "configured_addr")
444
- print(f"Account #{accid} ({addr}) imported successfully.")
445
+ print(f"Account #{accid} imported successfully.")
446
+
447
+
448
+ def _export_cmd(_cli: BotCli, bot: Bot, args: Namespace) -> None:
449
+ """export account backup"""
450
+ accid = _ensure_one_acc(bot, args)
451
+
452
+ if not args.folder.exists():
453
+ bot.logger.error(f"folder doesn't exist: {str(args.folder)!r}")
454
+ sys.exit(1)
455
+
456
+ try:
457
+ bot.rpc.export_backup(accid, str(args.folder), None)
458
+ except JsonRpcError as ex:
459
+ bot.logger.exception(ex)
460
+ sys.exit(1)
461
+ else:
462
+ print(f"Account #{accid} exported successfully.")
@@ -1,27 +1,24 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deltabot-cli
3
- Version: 7.2.0
3
+ Version: 8.1.0
4
4
  Summary: Library to speedup Delta Chat bot development
5
- Author-email: adbenitez <adb@merlinux.eu>
5
+ Author-email: adbenitez <adb@arcanechat.me>
6
6
  Project-URL: Homepage, https://github.com/deltachat-bot/deltabot-cli-py
7
7
  Keywords: deltachat,bot,deltabot-cli
8
8
  Classifier: Development Status :: 4 - Beta
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
12
- Requires-Python: >=3.8
12
+ Requires-Python: >=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: deltachat2[full]>=0.8.0
15
+ Requires-Dist: deltachat2[full]>=0.10.0
16
16
  Requires-Dist: appdirs>=1.4.4
17
17
  Requires-Dist: rich>=12.6.0
18
18
  Provides-Extra: dev
19
19
  Requires-Dist: black; extra == "dev"
20
- Requires-Dist: mypy; extra == "dev"
21
20
  Requires-Dist: isort; extra == "dev"
22
- Requires-Dist: pylint; extra == "dev"
23
- Requires-Dist: pylama; extra == "dev"
24
- Requires-Dist: pytest; extra == "dev"
21
+ Requires-Dist: prospector[with-mypy]; extra == "dev"
25
22
  Dynamic: license-file
26
23
 
27
24
  # deltabot-cli for Python
@@ -1,4 +1,5 @@
1
1
  .gitignore
2
+ .prospector.yaml
2
3
  LICENSE
3
4
  README.md
4
5
  pylama.ini
@@ -13,4 +14,5 @@ deltabot_cli.egg-info/dependency_links.txt
13
14
  deltabot_cli.egg-info/requires.txt
14
15
  deltabot_cli.egg-info/top_level.txt
15
16
  examples/echobot.py
16
- examples/echobot_advanced.py
17
+ examples/echobot_advanced.py
18
+ examples/send_and_exit.py
@@ -0,0 +1,8 @@
1
+ deltachat2[full]>=0.10.0
2
+ appdirs>=1.4.4
3
+ rich>=12.6.0
4
+
5
+ [dev]
6
+ black
7
+ isort
8
+ prospector[with-mypy]
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  """Advanced echo bot example."""
3
+
3
4
  from deltachat2 import EventType, MsgData, events
4
5
 
5
6
  from deltabot_cli import BotCli
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env python3
2
+ """An example bot that just sends a message and exits, without needing to be running all the time.
3
+ This useful, for example, for bots that are used only to send notifications/alerts,
4
+ and are integrated into other systems that would run the bot command with data parameters
5
+ every time there is a message to be sent.
6
+ """
7
+
8
+ from argparse import Namespace
9
+
10
+ from deltachat2 import Bot, EventType, MsgData, events
11
+
12
+ from deltabot_cli import BotCli
13
+
14
+ cli = BotCli("sendbot")
15
+
16
+
17
+ @cli.on(events.RawEvent)
18
+ def log_event(bot: Bot, _accid: int, event) -> None:
19
+ if event.kind == EventType.INFO:
20
+ bot.logger.debug(event.msg)
21
+ elif event.kind == EventType.WARNING:
22
+ bot.logger.warning(event.msg)
23
+ elif event.kind == EventType.ERROR:
24
+ bot.logger.error(event.msg)
25
+
26
+
27
+ def send(_cli: BotCli, bot: Bot, args: Namespace) -> None:
28
+ """send a message"""
29
+ accid = bot.rpc.get_all_account_ids()[0]
30
+
31
+ # first fetch incoming messages to have updated chats state
32
+ bot.logger.info("first syncing chats state...")
33
+ bot.rpc.accounts_background_fetch(60)
34
+
35
+ bot.logger.info("sending message...")
36
+ chatid = cli.get_admin_chat(bot.rpc, accid)
37
+ msgid = bot.rpc.send_msg(accid, chatid, MsgData(text=args.text, file=args.file))
38
+ bot.run_until(
39
+ lambda ev: ev.event.kind in (EventType.MSG_DELIVERED, EventType.MSG_FAILED)
40
+ and ev.event.msg_id == msgid
41
+ )
42
+ bot.logger.info("Done, message sent")
43
+
44
+
45
+ if __name__ == "__main__":
46
+ send_subcmd = cli.add_subcommand(send)
47
+ send_subcmd.add_argument("text", help="the message's text")
48
+ send_subcmd.add_argument(
49
+ "file",
50
+ nargs="?",
51
+ help="path to a file to send as attachment",
52
+ )
53
+ cli.start()
@@ -7,10 +7,10 @@ name = "deltabot-cli"
7
7
  description = "Library to speedup Delta Chat bot development"
8
8
  dynamic = ["version"]
9
9
  readme = "README.md"
10
- requires-python = ">=3.8"
10
+ requires-python = ">=3.10"
11
11
  keywords = ["deltachat", "bot", "deltabot-cli"]
12
12
  authors = [
13
- {name = "adbenitez", email = "adb@merlinux.eu"},
13
+ {name = "adbenitez", email = "adb@arcanechat.me"},
14
14
  ]
15
15
  classifiers = [
16
16
  "Development Status :: 4 - Beta",
@@ -19,7 +19,7 @@ classifiers = [
19
19
  "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
20
20
  ]
21
21
  dependencies = [
22
- "deltachat2[full]>=0.8.0",
22
+ "deltachat2[full]>=0.10.0",
23
23
  "appdirs>=1.4.4",
24
24
  "rich>=12.6.0",
25
25
  ]
@@ -30,11 +30,8 @@ Homepage = "https://github.com/deltachat-bot/deltabot-cli-py"
30
30
  [project.optional-dependencies]
31
31
  dev = [
32
32
  "black",
33
- "mypy",
34
33
  "isort",
35
- "pylint",
36
- "pylama",
37
- "pytest",
34
+ "prospector[with-mypy]",
38
35
  ]
39
36
 
40
37
  [tool.setuptools_scm]
@@ -1,11 +0,0 @@
1
- deltachat2[full]>=0.8.0
2
- appdirs>=1.4.4
3
- rich>=12.6.0
4
-
5
- [dev]
6
- black
7
- mypy
8
- isort
9
- pylint
10
- pylama
11
- pytest
File without changes
File without changes
File without changes
File without changes