diff --git a/python/conftest.py b/python/conftest.py index 0a90376a..54ec55ab 100644 --- a/python/conftest.py +++ b/python/conftest.py @@ -50,7 +50,7 @@ def acfactory(pytestconfig, tmpdir, request): tmpdb = tmpdir.join("livedb%d" % self.live_count) ac = Account(tmpdb.strpath, logid="ac{}".format(self.live_count)) ac._evlogger.set_timeout(30) - ac.set_config(**configdict) + ac.configure(**configdict) if started: ac.start() request.addfinalizer(ac.shutdown) diff --git a/python/src/deltachat/account.py b/python/src/deltachat/account.py index 6a776f35..c1122f33 100644 --- a/python/src/deltachat/account.py +++ b/python/src/deltachat/account.py @@ -23,7 +23,6 @@ class Account(object): by the underlying deltachat c-library. All public Account methods are meant to be memory-safe and return memory-safe objects. """ - def __init__(self, db_path, logid=None): """ initialize account object. @@ -32,10 +31,9 @@ class Account(object): :param logid: an optional logging prefix that should be used with the default internal logging. """ - self._dc_context = ffi.gc( lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL), - lib.dc_context_unref, + _destroy_dc_context, ) if hasattr(db_path, "encode"): db_path = db_path.encode("utf8") @@ -43,19 +41,21 @@ class Account(object): raise ValueError("Could not dc_open: {}".format(db_path)) self._evhandler = EventHandler(self._dc_context) self._evlogger = EventLogger(self._dc_context, logid) + deltachat.set_context_callback(self._dc_context, self._process_event) self._threads = IOThreads(self._dc_context) - def set_config(self, **kwargs): + def set_config(self, name, value): """ set configuration values. - :param kwargs: name=value settings for this account. - values need to be unicode. + :param name: config key name (unicode) + :param value: value to set (unicode) :returns: None """ - for name, value in kwargs.items(): - name = name.encode("utf8") - value = value.encode("utf8") - lib.dc_set_config(self._dc_context, name, value) + name = name.encode("utf8") + value = value.encode("utf8") + if name == b"addr" and self.is_configured(): + raise ValueError("can not change 'addr' after account is configured.") + lib.dc_set_config(self._dc_context, name, value) def get_config(self, name): """ return unicode string value. @@ -68,8 +68,20 @@ class Account(object): res = lib.dc_get_config(self._dc_context, name, b'') return from_dc_charpointer(res) + def configure(self, **kwargs): + """ set config values and configure this account. + + :param kwargs: name=value config settings for this account. + values need to be unicode. + :returns: None + """ + for name, value in kwargs.items(): + self.set_config(name, value) + lib.dc_configure(self._dc_context) + def is_configured(self): - """ determine if the account is configured already. + """ determine if the account is configured already; an initial connection + to SMTP/IMAP has been verified. :returns: True if account is configured. """ @@ -217,13 +229,12 @@ class Account(object): def start(self): """ configure this account object, start receiving events, start IMAP/SMTP threads. """ - deltachat.set_context_callback(self._dc_context, self._process_event) - lib.dc_configure(self._dc_context) + if not self.is_configured(): + self.configure() self._threads.start() def shutdown(self): """ shutdown IMAP/SMTP threads and stop receiving events""" - deltachat.clear_context_callback(self._dc_context) self._threads.stop(wait=True) def _process_event(self, ctx, evt_name, data1, data2): @@ -347,3 +358,14 @@ class EventLogger: tname = getattr(t, "name", t) print("[{}-{}] {}({!r},{!r})".format( tname, self.logid, evt_name, data1, data2)) + + +def _destroy_dc_context(dc_context, dc_context_unref=lib.dc_context_unref): + # destructor for dc_context + dc_context_unref(dc_context) + try: + deltachat.clear_context_callback(dc_context) + except (TypeError, AttributeError): + # we are deep into Python Interpreter shutdown, + # so no need to clear the callback context mapping. + pass diff --git a/python/tests/test_account.py b/python/tests/test_account.py index 74870e3f..4833a449 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -125,6 +125,10 @@ class TestOnlineAccount: self.wait_configuration_progress(ac1, 1000) assert ac1.get_config("mail_pw") assert ac1.is_configured() + with pytest.raises(ValueError): + ac1.set_config("addr", "123@example.org") + with pytest.raises(ValueError): + ac1.configure(addr="123@example.org") def test_forward_messages(self, acfactory): ac1 = acfactory.get_live_account()