diff --git a/python/src/deltachat/__init__.py b/python/src/deltachat/__init__.py index 25626021..ec43f4a5 100644 --- a/python/src/deltachat/__init__.py +++ b/python/src/deltachat/__init__.py @@ -1,4 +1,4 @@ -from deltachat import capi +from deltachat import capi, const from deltachat.capi import ffi from deltachat.account import Account # noqa @@ -58,7 +58,7 @@ def clear_context_callback(dc_context): def get_dc_event_name(integer, _DC_EVENTNAME_MAP={}): if not _DC_EVENTNAME_MAP: - for name, val in vars(capi.lib).items(): + for name, val in vars(const).items(): if name.startswith("DC_EVENT_"): _DC_EVENTNAME_MAP[val] = name return _DC_EVENTNAME_MAP[integer] diff --git a/python/src/deltachat/_build.py b/python/src/deltachat/_build.py index 94dd6a3d..467c2a4f 100644 --- a/python/src/deltachat/_build.py +++ b/python/src/deltachat/_build.py @@ -1,20 +1,8 @@ import distutils.ccompiler import distutils.sysconfig import tempfile -import re -from os.path import dirname, abspath -from os.path import join as joinpath - import cffi -here = dirname(abspath(__file__)) -deltah = joinpath(dirname(dirname(dirname(here))), "src", "deltachat.h") - - -def read_event_defines(): - rex = re.compile(r'#define\s+(?:DC_EVENT_|DC_STATE_|DC_CONTACT_ID_|DC_GCL|DC_CHAT)\S+\s+([x\d]+).*') - return filter(rex.match, open(deltah)) - def ffibuilder(): builder = cffi.FFI() @@ -65,8 +53,6 @@ def ffibuilder(): uintptr_t data1, uintptr_t data2); """) - event_defines = "\n".join(read_event_defines()) - builder.cdef(event_defines) return builder diff --git a/python/src/deltachat/account.py b/python/src/deltachat/account.py index c6017494..92eafdd3 100644 --- a/python/src/deltachat/account.py +++ b/python/src/deltachat/account.py @@ -13,6 +13,7 @@ import attr from attr import validators as v import deltachat +from . import const from .capi import ffi, lib from .cutil import as_dc_charpointer, from_dc_charpointer, iter_array from .chatting import Contact, Chat, Message @@ -100,7 +101,7 @@ class Account(object): :returns: :class:`Contact` """ self.check_is_configured() - return Contact(self._dc_context, lib.DC_CONTACT_ID_SELF) + return Contact(self._dc_context, const.DC_CONTACT_ID_SELF) def create_contact(self, email, name=None): """ create a (new) Contact. If there already is a Contact @@ -114,7 +115,7 @@ class Account(object): name = as_dc_charpointer(name) email = as_dc_charpointer(email) contact_id = lib.dc_create_contact(self._dc_context, name, email) - assert contact_id > lib.DC_CHAT_ID_LAST_SPECIAL + assert contact_id > const.DC_CHAT_ID_LAST_SPECIAL return Contact(self._dc_context, contact_id) def get_contacts(self, query=None, with_self=False, only_verified=False): @@ -129,9 +130,9 @@ class Account(object): flags = 0 query = as_dc_charpointer(query) if only_verified: - flags |= lib.DC_GCL_VERIFIED_ONLY + flags |= const.DC_GCL_VERIFIED_ONLY if with_self: - flags |= lib.DC_GCL_ADD_SELF + flags |= const.DC_GCL_ADD_SELF dc_array = ffi.gc( lib.dc_get_contacts(self._dc_context, flags, query), lib.dc_array_unref @@ -192,7 +193,7 @@ class Account(object): return chatlist def get_deaddrop_chat(self): - return Chat(self._dc_context, lib.DC_CHAT_ID_DEADDROP) + return Chat(self._dc_context, const.DC_CHAT_ID_DEADDROP) def get_message_by_id(self, msg_id): """ return Message instance. """ diff --git a/python/src/deltachat/chatting.py b/python/src/deltachat/chatting.py index dba57a43..352275f3 100644 --- a/python/src/deltachat/chatting.py +++ b/python/src/deltachat/chatting.py @@ -3,6 +3,7 @@ from .cutil import as_dc_charpointer, from_dc_charpointer, iter_array from .capi import lib, ffi from .types import property_with_doc +from . import const from datetime import datetime import attr from attr import validators as v @@ -66,7 +67,7 @@ class Chat(object): :returns: True if chat is the deaddrop chat, False otherwise. """ - return self.id == lib.DC_CHAT_ID_DEADDROP + return self.id == const.DC_CHAT_ID_DEADDROP def is_promoted(self): """ return True if this chat is promoted, i.e. @@ -231,7 +232,7 @@ class MessageState(object): Fresh messages are not noticed nor seen and are typically shown in notifications. """ - return self._msgstate == lib.DC_STATE_IN_FRESH + return self._msgstate == const.DC_STATE_IN_FRESH def is_in_noticed(self): """Return True if Message is incoming and noticed. @@ -239,7 +240,7 @@ class MessageState(object): Eg. chat opened but message not yet read - noticed messages are not counted as unread but were not marked as read nor resulted in MDNs. """ - return self._msgstate == lib.DC_STATE_IN_NOTICED + return self._msgstate == const.DC_STATE_IN_NOTICED def is_in_seen(self): """Return True if Message is incoming, noticed and has been seen. @@ -247,28 +248,28 @@ class MessageState(object): Eg. chat opened but message not yet read - noticed messages are not counted as unread but were not marked as read nor resulted in MDNs. """ - return self._msgstate == lib.DC_STATE_IN_SEEN + return self._msgstate == const.DC_STATE_IN_SEEN def is_out_pending(self): """Return True if Message is outgoing, but is pending (no single checkmark). """ - return self._msgstate == lib.DC_STATE_OUT_PENDING + return self._msgstate == const.DC_STATE_OUT_PENDING def is_out_failed(self): """Return True if Message is unrecoverably failed. """ - return self._msgstate == lib.DC_STATE_OUT_FAILED + return self._msgstate == const.DC_STATE_OUT_FAILED def is_out_delivered(self): """Return True if Message was successfully delivered to the server (one checkmark). Note, that already delivered messages may get into the state is_out_failed(). """ - return self._msgstate == lib.DC_STATE_OUT_DELIVERED + return self._msgstate == const.DC_STATE_OUT_DELIVERED def is_out_mdn_received(self): """Return True if message was marked as read by the recipient(s) (two checkmarks; this requires goodwill on the receiver's side). If a sent message changes to this state, you'll receive the event DC_EVENT_MSG_READ. """ - return self._msgstate == lib.DC_STATE_OUT_MDN_RCVD + return self._msgstate == const.DC_STATE_OUT_MDN_RCVD diff --git a/python/src/deltachat/const.py b/python/src/deltachat/const.py new file mode 100644 index 00000000..7d91a05a --- /dev/null +++ b/python/src/deltachat/const.py @@ -0,0 +1,98 @@ +import sys +import re +import os +from os.path import dirname, abspath +from os.path import join as joinpath + +# the following const are generated from deltachat.h +# this works well when you in a git-checkout +# run "python deltachat/const.py" to regenerate events +# begin const generated +DC_GCL_ARCHIVED_ONLY = 0x01 +DC_GCL_NO_SPECIALS = 0x02 +DC_GCL_ADD_ALLDONE_HINT = 0x04 +DC_GCL_VERIFIED_ONLY = 0x01 +DC_GCL_ADD_SELF = 0x02 +DC_CHAT_ID_DEADDROP = 1 +DC_CHAT_ID_TRASH = 3 +DC_CHAT_ID_MSGS_IN_CREATION = 4 +DC_CHAT_ID_STARRED = 5 +DC_CHAT_ID_ARCHIVED_LINK = 6 +DC_CHAT_ID_ALLDONE_HINT = 7 +DC_CHAT_ID_LAST_SPECIAL = 9 +DC_CHAT_TYPE_UNDEFINED = 0 +DC_CHAT_TYPE_SINGLE = 100 +DC_CHAT_TYPE_GROUP = 120 +DC_CHAT_TYPE_VERIFIED_GROUP = 130 +DC_STATE_UNDEFINED = 0 +DC_STATE_IN_FRESH = 10 +DC_STATE_IN_NOTICED = 13 +DC_STATE_IN_SEEN = 16 +DC_STATE_OUT_PENDING = 20 +DC_STATE_OUT_FAILED = 24 +DC_STATE_OUT_DELIVERED = 26 +DC_STATE_OUT_MDN_RCVD = 28 +DC_CONTACT_ID_SELF = 1 +DC_CONTACT_ID_DEVICE = 2 +DC_CONTACT_ID_LAST_SPECIAL = 9 +DC_EVENT_INFO = 100 +DC_EVENT_SMTP_CONNECTED = 101 +DC_EVENT_IMAP_CONNECTED = 102 +DC_EVENT_SMTP_MESSAGE_SENT = 103 +DC_EVENT_WARNING = 300 +DC_EVENT_ERROR = 400 +DC_EVENT_MSGS_CHANGED = 2000 +DC_EVENT_INCOMING_MSG = 2005 +DC_EVENT_MSG_DELIVERED = 2010 +DC_EVENT_MSG_FAILED = 2012 +DC_EVENT_MSG_READ = 2015 +DC_EVENT_CHAT_MODIFIED = 2020 +DC_EVENT_CONTACTS_CHANGED = 2030 +DC_EVENT_CONFIGURE_PROGRESS = 2041 +DC_EVENT_IMEX_PROGRESS = 2051 +DC_EVENT_IMEX_FILE_WRITTEN = 2052 +DC_EVENT_FILE_COPIED = 2055 +DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060 +DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061 +DC_EVENT_IS_OFFLINE = 2081 +DC_EVENT_GET_STRING = 2091 +DC_EVENT_GET_QUANTITY_STRING = 2092 +DC_EVENT_HTTP_GET = 2100 +# end const generated + + +def read_event_defines(f): + rex = re.compile(r'#define\s+((?:DC_EVENT_|DC_STATE_|DC_CONTACT_ID_|DC_GCL|DC_CHAT)\S+)\s+([x\d]+).*') + for line in f: + m = rex.match(line) + if m: + yield m.groups() + + +if __name__ == "__main__": + here = abspath(__file__).rstrip("oc") + here_dir = dirname(here) + if len(sys.argv) >= 2: + deltah = sys.argv[1] + else: + deltah = joinpath(dirname(dirname(dirname(here_dir))), "src", "deltachat.h") + assert os.path.exists(deltah) + + lines = [] + skip_to_end = False + for orig_line in open(here): + if skip_to_end: + if not orig_line.startswith("# end const"): + continue + skip_to_end = False + lines.append(orig_line) + if orig_line.startswith("# begin const"): + with open(deltah) as f: + for name, item in read_event_defines(f): + lines.append("{} = {}\n".format(name, item)) + skip_to_end = True + + tmpname = here + ".tmp" + with open(tmpname, "w") as f: + f.write("".join(lines)) + os.rename(tmpname, here) diff --git a/python/tests/test_account.py b/python/tests/test_account.py index 7c289259..492f09ce 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -1,6 +1,6 @@ from __future__ import print_function import pytest -from deltachat.capi import lib +from deltachat import const from datetime import datetime, timedelta from conftest import wait_configuration_progress, wait_successful_IMAP_SMTP_connection @@ -54,7 +54,7 @@ class TestOfflineAccount: ac1 = acfactory.get_configured_offline_account() contact1 = ac1.create_contact("some1@hello.com", name="some1") chat = ac1.create_chat_by_contact(contact1) - assert chat.id >= lib.DC_CHAT_ID_LAST_SPECIAL, chat.id + assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL, chat.id chat2 = ac1.create_chat_by_contact(contact1.id) assert chat2.id == chat.id @@ -125,7 +125,7 @@ class TestOnlineAccount: ac2 = acfactory.get_online_configuring_account() c2 = ac1.create_contact(email=ac2.get_config("addr")) chat = ac1.create_chat_by_contact(c2) - assert chat.id >= lib.DC_CHAT_ID_LAST_SPECIAL + assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL wait_successful_IMAP_SMTP_connection(ac1) wait_configuration_progress(ac1, 1000) wait_successful_IMAP_SMTP_connection(ac2) @@ -158,7 +158,7 @@ class TestOnlineAccount: ac2 = acfactory.get_online_configuring_account() c2 = ac1.create_contact(email=ac2.get_config("addr")) chat = ac1.create_chat_by_contact(c2) - assert chat.id >= lib.DC_CHAT_ID_LAST_SPECIAL + assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL wait_configuration_progress(ac1, 1000) wait_configuration_progress(ac2, 1000) diff --git a/python/tests/test_lowlevel.py b/python/tests/test_lowlevel.py index da26c6ff..e3c5705b 100644 --- a/python/tests/test_lowlevel.py +++ b/python/tests/test_lowlevel.py @@ -1,6 +1,6 @@ from __future__ import print_function import pytest -from deltachat import capi, Account +from deltachat import capi, Account, const def test_empty_context(): @@ -15,15 +15,15 @@ def test_wrong_db(tmpdir): def test_event_defines(): - assert capi.lib.DC_EVENT_INFO == 100 - assert capi.lib.DC_CONTACT_ID_SELF + assert const.DC_EVENT_INFO == 100 + assert const.DC_CONTACT_ID_SELF def test_sig(): sig = capi.lib.dc_get_event_signature_types - assert sig(capi.lib.DC_EVENT_INFO) == 2 - assert sig(capi.lib.DC_EVENT_WARNING) == 2 - assert sig(capi.lib.DC_EVENT_ERROR) == 2 - assert sig(capi.lib.DC_EVENT_SMTP_CONNECTED) == 2 - assert sig(capi.lib.DC_EVENT_IMAP_CONNECTED) == 2 - assert sig(capi.lib.DC_EVENT_SMTP_MESSAGE_SENT) == 2 + assert sig(const.DC_EVENT_INFO) == 2 + assert sig(const.DC_EVENT_WARNING) == 2 + assert sig(const.DC_EVENT_ERROR) == 2 + assert sig(const.DC_EVENT_SMTP_CONNECTED) == 2 + assert sig(const.DC_EVENT_IMAP_CONNECTED) == 2 + assert sig(const.DC_EVENT_SMTP_MESSAGE_SENT) == 2