mirror of
https://github.com/deltachat/deltachat-core.git
synced 2025-10-04 18:29:19 +02:00
move all unref'in to a specific shadow class that takes care of unref'ing.
bump version
This commit is contained in:
parent
da2bcd0c5a
commit
8c1c65b631
6 changed files with 120 additions and 97 deletions
|
@ -2,7 +2,7 @@ from deltachat import capi
|
||||||
from deltachat.capi import ffi
|
from deltachat.capi import ffi
|
||||||
from deltachat.account import Account # noqa
|
from deltachat.account import Account # noqa
|
||||||
|
|
||||||
__version__ = "0.5.dev1"
|
__version__ = "0.5.dev2"
|
||||||
|
|
||||||
|
|
||||||
_DC_CALLBACK_MAP = {}
|
_DC_CALLBACK_MAP = {}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
""" Delta.Chat Account class. """
|
""" Account class implementation. """
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import threading
|
import threading
|
||||||
|
@ -9,13 +9,13 @@ try:
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from Queue import Queue
|
from Queue import Queue
|
||||||
|
|
||||||
import deltachat
|
|
||||||
from . import capi
|
|
||||||
from .cutil import convert_to_bytes_utf8, ffi_unicode, iter_array_and_unref
|
|
||||||
from .capi import ffi, lib
|
|
||||||
import attr
|
import attr
|
||||||
from attr import validators as v
|
from attr import validators as v
|
||||||
|
|
||||||
|
import deltachat
|
||||||
|
from .capi import ffi, lib
|
||||||
|
from .cutil import convert_to_bytes_utf8, ffi_unicode, iter_array_and_unref
|
||||||
|
from .types import DC_Context
|
||||||
from .chatting import Contact, Chat, Message
|
from .chatting import Contact, Chat, Message
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ class Account(object):
|
||||||
""" An account contains configuration and provides methods
|
""" An account contains configuration and provides methods
|
||||||
for configuration, contact and chat creation and manipulation.
|
for configuration, contact and chat creation and manipulation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, db_path, logid=None):
|
def __init__(self, db_path, logid=None):
|
||||||
""" initialize account object.
|
""" initialize account object.
|
||||||
|
|
||||||
|
@ -32,19 +33,16 @@ class Account(object):
|
||||||
the default internal logging.
|
the default internal logging.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.dc_context = ctx = capi.lib.dc_context_new(
|
self._dc_context = DC_Context(
|
||||||
capi.lib.py_dc_callback,
|
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL)
|
||||||
capi.ffi.NULL, capi.ffi.NULL)
|
)
|
||||||
if hasattr(db_path, "encode"):
|
if hasattr(db_path, "encode"):
|
||||||
db_path = db_path.encode("utf8")
|
db_path = db_path.encode("utf8")
|
||||||
capi.lib.dc_open(ctx, db_path, capi.ffi.NULL)
|
if not lib.dc_open(self._dc_context.p, db_path, ffi.NULL):
|
||||||
self._evhandler = EventHandler(self.dc_context)
|
raise ValueError("Could not dc_open: {}".format(db_path))
|
||||||
self._evlogger = EventLogger(self.dc_context, logid)
|
self._evhandler = EventHandler(self._dc_context)
|
||||||
self._threads = IOThreads(self.dc_context)
|
self._evlogger = EventLogger(self._dc_context, logid)
|
||||||
|
self._threads = IOThreads(self._dc_context)
|
||||||
def __del__(self):
|
|
||||||
if lib is not None:
|
|
||||||
lib.dc_context_unref(self.dc_context)
|
|
||||||
|
|
||||||
def set_config(self, **kwargs):
|
def set_config(self, **kwargs):
|
||||||
""" set configuration values.
|
""" set configuration values.
|
||||||
|
@ -56,7 +54,7 @@ class Account(object):
|
||||||
for name, value in kwargs.items():
|
for name, value in kwargs.items():
|
||||||
name = name.encode("utf8")
|
name = name.encode("utf8")
|
||||||
value = value.encode("utf8")
|
value = value.encode("utf8")
|
||||||
capi.lib.dc_set_config(self.dc_context, name, value)
|
lib.dc_set_config(self._dc_context.p, name, value)
|
||||||
|
|
||||||
def get_config(self, name):
|
def get_config(self, name):
|
||||||
""" return unicode string value.
|
""" return unicode string value.
|
||||||
|
@ -65,7 +63,7 @@ class Account(object):
|
||||||
:returns: unicode value
|
:returns: unicode value
|
||||||
"""
|
"""
|
||||||
name = name.encode("utf8")
|
name = name.encode("utf8")
|
||||||
res = capi.lib.dc_get_config(self.dc_context, name, b'')
|
res = lib.dc_get_config(self._dc_context.p, name, b'')
|
||||||
return ffi_unicode(res)
|
return ffi_unicode(res)
|
||||||
|
|
||||||
def is_configured(self):
|
def is_configured(self):
|
||||||
|
@ -73,7 +71,7 @@ class Account(object):
|
||||||
|
|
||||||
:returns: True if account is configured.
|
:returns: True if account is configured.
|
||||||
"""
|
"""
|
||||||
return capi.lib.dc_is_configured(self.dc_context)
|
return lib.dc_is_configured(self._dc_context.p)
|
||||||
|
|
||||||
def check_is_configured(self):
|
def check_is_configured(self):
|
||||||
""" Raise ValueError if this account is not configured. """
|
""" Raise ValueError if this account is not configured. """
|
||||||
|
@ -86,7 +84,7 @@ class Account(object):
|
||||||
:returns: :class:`Contact`
|
:returns: :class:`Contact`
|
||||||
"""
|
"""
|
||||||
self.check_is_configured()
|
self.check_is_configured()
|
||||||
return Contact(self.dc_context, capi.lib.DC_CONTACT_ID_SELF)
|
return Contact(self._dc_context, lib.DC_CONTACT_ID_SELF)
|
||||||
|
|
||||||
def create_contact(self, email, name=ffi.NULL):
|
def create_contact(self, email, name=ffi.NULL):
|
||||||
""" create a (new) Contact. If there already is a Contact
|
""" create a (new) Contact. If there already is a Contact
|
||||||
|
@ -99,8 +97,8 @@ class Account(object):
|
||||||
"""
|
"""
|
||||||
name = convert_to_bytes_utf8(name)
|
name = convert_to_bytes_utf8(name)
|
||||||
email = convert_to_bytes_utf8(email)
|
email = convert_to_bytes_utf8(email)
|
||||||
contact_id = capi.lib.dc_create_contact(self.dc_context, name, email)
|
contact_id = lib.dc_create_contact(self._dc_context.p, name, email)
|
||||||
return Contact(self.dc_context, contact_id)
|
return Contact(self._dc_context, contact_id)
|
||||||
|
|
||||||
def get_contacts(self, query=ffi.NULL, with_self=False, only_verified=False):
|
def get_contacts(self, query=ffi.NULL, with_self=False, only_verified=False):
|
||||||
""" get a (filtered) list of contacts.
|
""" get a (filtered) list of contacts.
|
||||||
|
@ -117,8 +115,8 @@ class Account(object):
|
||||||
flags |= lib.DC_GCL_VERIFIED_ONLY
|
flags |= lib.DC_GCL_VERIFIED_ONLY
|
||||||
if with_self:
|
if with_self:
|
||||||
flags |= lib.DC_GCL_ADD_SELF
|
flags |= lib.DC_GCL_ADD_SELF
|
||||||
dc_array_t = lib.dc_get_contacts(self.dc_context, flags, query)
|
dc_array_t = lib.dc_get_contacts(self._dc_context.p, flags, query)
|
||||||
return list(iter_array_and_unref(dc_array_t, lambda x: Contact(self.dc_context, x)))
|
return list(iter_array_and_unref(dc_array_t, lambda x: Contact(self._dc_context.p, x)))
|
||||||
|
|
||||||
def create_chat_by_contact(self, contact):
|
def create_chat_by_contact(self, contact):
|
||||||
""" create or get an existing 1:1 chat object for the specified contact.
|
""" create or get an existing 1:1 chat object for the specified contact.
|
||||||
|
@ -128,9 +126,9 @@ class Account(object):
|
||||||
"""
|
"""
|
||||||
contact_id = getattr(contact, "id", contact)
|
contact_id = getattr(contact, "id", contact)
|
||||||
assert isinstance(contact_id, int)
|
assert isinstance(contact_id, int)
|
||||||
chat_id = capi.lib.dc_create_chat_by_contact_id(
|
chat_id = lib.dc_create_chat_by_contact_id(
|
||||||
self.dc_context, contact_id)
|
self._dc_context.p, contact_id)
|
||||||
return Chat(self.dc_context, chat_id)
|
return Chat(self._dc_context, chat_id)
|
||||||
|
|
||||||
def create_chat_by_message(self, message):
|
def create_chat_by_message(self, message):
|
||||||
""" create or get an existing 1:1 chat object for the specified sender
|
""" create or get an existing 1:1 chat object for the specified sender
|
||||||
|
@ -141,12 +139,12 @@ class Account(object):
|
||||||
"""
|
"""
|
||||||
msg_id = getattr(message, "id", message)
|
msg_id = getattr(message, "id", message)
|
||||||
assert isinstance(msg_id, int)
|
assert isinstance(msg_id, int)
|
||||||
chat_id = capi.lib.dc_create_chat_by_msg_id(self.dc_context, msg_id)
|
chat_id = lib.dc_create_chat_by_msg_id(self._dc_context.p, msg_id)
|
||||||
return Chat(self.dc_context, chat_id)
|
return Chat(self._dc_context, chat_id)
|
||||||
|
|
||||||
def get_message_by_id(self, msg_id):
|
def get_message_by_id(self, msg_id):
|
||||||
""" return Message instance. """
|
""" return Message instance. """
|
||||||
return Message(self.dc_context, msg_id)
|
return Message(self._dc_context, msg_id)
|
||||||
|
|
||||||
def mark_seen_messages(self, messages):
|
def mark_seen_messages(self, messages):
|
||||||
""" mark the given set of messages as seen.
|
""" mark the given set of messages as seen.
|
||||||
|
@ -158,22 +156,22 @@ class Account(object):
|
||||||
msg = getattr(msg, "id", msg)
|
msg = getattr(msg, "id", msg)
|
||||||
arr.append(msg)
|
arr.append(msg)
|
||||||
msg_ids = ffi.cast("uint32_t*", ffi.from_buffer(arr))
|
msg_ids = ffi.cast("uint32_t*", ffi.from_buffer(arr))
|
||||||
lib.dc_markseen_msgs(self.dc_context, msg_ids, len(messages))
|
lib.dc_markseen_msgs(self._dc_context.p, msg_ids, len(messages))
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
""" configure this account object, start receiving events,
|
""" configure this account object, start receiving events,
|
||||||
start IMAP/SMTP threads. """
|
start IMAP/SMTP threads. """
|
||||||
deltachat.set_context_callback(self.dc_context, self._process_event)
|
deltachat.set_context_callback(self._dc_context.p, self._process_event)
|
||||||
capi.lib.dc_configure(self.dc_context)
|
lib.dc_configure(self._dc_context.p)
|
||||||
self._threads.start()
|
self._threads.start()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
""" shutdown IMAP/SMTP threads and stop receiving events"""
|
""" shutdown IMAP/SMTP threads and stop receiving events"""
|
||||||
deltachat.clear_context_callback(self.dc_context)
|
deltachat.clear_context_callback(self._dc_context.p)
|
||||||
self._threads.stop(wait=True)
|
self._threads.stop(wait=True)
|
||||||
|
|
||||||
def _process_event(self, ctx, evt_name, data1, data2):
|
def _process_event(self, ctx, evt_name, data1, data2):
|
||||||
assert ctx == self.dc_context
|
assert ctx == self._dc_context.p
|
||||||
self._evlogger(evt_name, data1, data2)
|
self._evlogger(evt_name, data1, data2)
|
||||||
method = getattr(self._evhandler, evt_name.lower(), None)
|
method = getattr(self._evhandler, evt_name.lower(), None)
|
||||||
if method is not None:
|
if method is not None:
|
||||||
|
@ -183,7 +181,7 @@ class Account(object):
|
||||||
|
|
||||||
class IOThreads:
|
class IOThreads:
|
||||||
def __init__(self, dc_context):
|
def __init__(self, dc_context):
|
||||||
self.dc_context = dc_context
|
self._dc_context = dc_context
|
||||||
self._thread_quitflag = False
|
self._thread_quitflag = False
|
||||||
self._name2thread = {}
|
self._name2thread = {}
|
||||||
|
|
||||||
|
@ -201,8 +199,8 @@ class IOThreads:
|
||||||
|
|
||||||
def stop(self, wait=False):
|
def stop(self, wait=False):
|
||||||
self._thread_quitflag = True
|
self._thread_quitflag = True
|
||||||
capi.lib.dc_interrupt_imap_idle(self.dc_context)
|
lib.dc_interrupt_imap_idle(self._dc_context.p)
|
||||||
capi.lib.dc_interrupt_smtp_idle(self.dc_context)
|
lib.dc_interrupt_smtp_idle(self._dc_context.p)
|
||||||
if wait:
|
if wait:
|
||||||
for name, thread in self._name2thread.items():
|
for name, thread in self._name2thread.items():
|
||||||
thread.join()
|
thread.join()
|
||||||
|
@ -210,20 +208,20 @@ class IOThreads:
|
||||||
def imap_thread_run(self):
|
def imap_thread_run(self):
|
||||||
print ("starting imap thread")
|
print ("starting imap thread")
|
||||||
while not self._thread_quitflag:
|
while not self._thread_quitflag:
|
||||||
capi.lib.dc_perform_imap_jobs(self.dc_context)
|
lib.dc_perform_imap_jobs(self._dc_context.p)
|
||||||
capi.lib.dc_perform_imap_fetch(self.dc_context)
|
lib.dc_perform_imap_fetch(self._dc_context.p)
|
||||||
capi.lib.dc_perform_imap_idle(self.dc_context)
|
lib.dc_perform_imap_idle(self._dc_context.p)
|
||||||
|
|
||||||
def smtp_thread_run(self):
|
def smtp_thread_run(self):
|
||||||
print ("starting smtp thread")
|
print ("starting smtp thread")
|
||||||
while not self._thread_quitflag:
|
while not self._thread_quitflag:
|
||||||
capi.lib.dc_perform_smtp_jobs(self.dc_context)
|
lib.dc_perform_smtp_jobs(self._dc_context.p)
|
||||||
capi.lib.dc_perform_smtp_idle(self.dc_context)
|
lib.dc_perform_smtp_idle(self._dc_context.p)
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
class EventHandler(object):
|
class EventHandler(object):
|
||||||
dc_context = attr.ib(validator=v.instance_of(ffi.CData))
|
_dc_context = attr.ib(validator=v.instance_of(DC_Context))
|
||||||
|
|
||||||
def read_url(self, url):
|
def read_url(self, url):
|
||||||
try:
|
try:
|
||||||
|
@ -239,7 +237,7 @@ class EventHandler(object):
|
||||||
if not isinstance(content, bytes):
|
if not isinstance(content, bytes):
|
||||||
content = content.encode("utf8")
|
content = content.encode("utf8")
|
||||||
# we need to return a fresh pointer that the core owns
|
# we need to return a fresh pointer that the core owns
|
||||||
return capi.lib.dupstring_helper(content)
|
return lib.dupstring_helper(content)
|
||||||
|
|
||||||
def dc_event_is_offline(self, data1, data2):
|
def dc_event_is_offline(self, data1, data2):
|
||||||
return 0 # always online
|
return 0 # always online
|
||||||
|
@ -247,11 +245,11 @@ class EventHandler(object):
|
||||||
|
|
||||||
class EventLogger:
|
class EventLogger:
|
||||||
def __init__(self, dc_context, logid=None, debug=True):
|
def __init__(self, dc_context, logid=None, debug=True):
|
||||||
self.dc_context = dc_context
|
self._dc_context = dc_context
|
||||||
self._event_queue = Queue()
|
self._event_queue = Queue()
|
||||||
self._debug = debug
|
self._debug = debug
|
||||||
if logid is None:
|
if logid is None:
|
||||||
logid = str(self.dc_context).strip(">").split()[-1]
|
logid = str(self._dc_context.p).strip(">").split()[-1]
|
||||||
self.logid = logid
|
self.logid = logid
|
||||||
self._timeout = None
|
self._timeout = None
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
""" chatting related objects: Contact, Chat, Message. """
|
""" chatting related objects: Contact, Chat, Message. """
|
||||||
|
|
||||||
from . import capi
|
|
||||||
from .cutil import convert_to_bytes_utf8, ffi_unicode, iter_array_and_unref
|
from .cutil import convert_to_bytes_utf8, ffi_unicode, iter_array_and_unref
|
||||||
from .capi import ffi, lib
|
from .capi import lib
|
||||||
from .types import cached_property, property_with_doc
|
from .types import cached_property, property_with_doc
|
||||||
|
from .types import DC_Context, DC_Contact, DC_Chat, DC_Msg
|
||||||
import attr
|
import attr
|
||||||
from attr import validators as v
|
from attr import validators as v
|
||||||
|
|
||||||
|
@ -14,34 +14,30 @@ class Contact(object):
|
||||||
|
|
||||||
You obtain instances of it through :class:`deltachat.account.Account`.
|
You obtain instances of it through :class:`deltachat.account.Account`.
|
||||||
"""
|
"""
|
||||||
dc_context = attr.ib(validator=v.instance_of(ffi.CData))
|
_dc_context = attr.ib(validator=v.instance_of(DC_Context))
|
||||||
id = attr.ib(validator=v.instance_of(int))
|
id = attr.ib(validator=v.instance_of(int))
|
||||||
|
|
||||||
@cached_property # only get it once because we only free it once
|
@cached_property
|
||||||
def dc_contact_t(self):
|
def _dc_contact(self):
|
||||||
return capi.lib.dc_get_contact(self.dc_context, self.id)
|
return DC_Contact(lib.dc_get_contact(self._dc_context.p, self.id))
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
if lib is not None and hasattr(self, "_property_cache"):
|
|
||||||
lib.dc_contact_unref(self.dc_contact_t)
|
|
||||||
|
|
||||||
@property_with_doc
|
@property_with_doc
|
||||||
def addr(self):
|
def addr(self):
|
||||||
""" normalized e-mail address for this account. """
|
""" normalized e-mail address for this account. """
|
||||||
return ffi_unicode(capi.lib.dc_contact_get_addr(self.dc_contact_t))
|
return ffi_unicode(lib.dc_contact_get_addr(self._dc_contact.p))
|
||||||
|
|
||||||
@property_with_doc
|
@property_with_doc
|
||||||
def display_name(self):
|
def display_name(self):
|
||||||
""" display name for this contact. """
|
""" display name for this contact. """
|
||||||
return ffi_unicode(capi.lib.dc_contact_get_display_name(self.dc_contact_t))
|
return ffi_unicode(lib.dc_contact_get_display_name(self._dc_contact.p))
|
||||||
|
|
||||||
def is_blocked(self):
|
def is_blocked(self):
|
||||||
""" Return True if the contact is blocked. """
|
""" Return True if the contact is blocked. """
|
||||||
return capi.lib.dc_contact_is_blocked(self.dc_contact_t)
|
return lib.dc_contact_is_blocked(self._dc_contact.p)
|
||||||
|
|
||||||
def is_verified(self):
|
def is_verified(self):
|
||||||
""" Return True if the contact is verified. """
|
""" Return True if the contact is verified. """
|
||||||
return capi.lib.dc_contact_is_verified(self.dc_contact_t)
|
return lib.dc_contact_is_verified(self._dc_contact.p)
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
|
@ -50,17 +46,12 @@ class Chat(object):
|
||||||
|
|
||||||
You obtain instances of it through :class:`deltachat.account.Account`.
|
You obtain instances of it through :class:`deltachat.account.Account`.
|
||||||
"""
|
"""
|
||||||
|
_dc_context = attr.ib(validator=v.instance_of(DC_Context))
|
||||||
dc_context = attr.ib(validator=v.instance_of(ffi.CData))
|
|
||||||
id = attr.ib(validator=v.instance_of(int))
|
id = attr.ib(validator=v.instance_of(int))
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def dc_chat_t(self):
|
def _dc_chat(self):
|
||||||
return capi.lib.dc_get_chat(self.dc_context, self.id)
|
return DC_Chat(lib.dc_get_chat(self._dc_context.p, self.id))
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
if lib is not None and hasattr(self, "_property_cache"):
|
|
||||||
lib.dc_chat_unref(self.dc_chat_t)
|
|
||||||
|
|
||||||
def is_deaddrop(self):
|
def is_deaddrop(self):
|
||||||
""" return true if this chat is a deaddrop chat. """
|
""" return true if this chat is a deaddrop chat. """
|
||||||
|
@ -73,31 +64,30 @@ class Chat(object):
|
||||||
:returns: the resulting :class:`Message` instance
|
:returns: the resulting :class:`Message` instance
|
||||||
"""
|
"""
|
||||||
msg = convert_to_bytes_utf8(msg)
|
msg = convert_to_bytes_utf8(msg)
|
||||||
print ("chat id", self.id)
|
msg_id = lib.dc_send_text_msg(self._dc_context.p, self.id, msg)
|
||||||
msg_id = capi.lib.dc_send_text_msg(self.dc_context, self.id, msg)
|
return Message(self._dc_context, msg_id)
|
||||||
return Message(self.dc_context, msg_id)
|
|
||||||
|
|
||||||
def get_messages(self):
|
def get_messages(self):
|
||||||
""" return list of messages in this chat.
|
""" return list of messages in this chat.
|
||||||
|
|
||||||
:returns: list of :class:`Message` objects for this chat.
|
:returns: list of :class:`Message` objects for this chat.
|
||||||
"""
|
"""
|
||||||
dc_array_t = lib.dc_get_chat_msgs(self.dc_context, self.id, 0, 0)
|
dc_array_t = lib.dc_get_chat_msgs(self._dc_context.p, self.id, 0, 0)
|
||||||
return list(iter_array_and_unref(dc_array_t, lambda x: Message(self.dc_context, x)))
|
return list(iter_array_and_unref(dc_array_t, lambda x: Message(self._dc_context, x)))
|
||||||
|
|
||||||
def count_fresh_messages(self):
|
def count_fresh_messages(self):
|
||||||
""" return number of fresh messages in this chat.
|
""" return number of fresh messages in this chat.
|
||||||
|
|
||||||
:returns: number of fresh messages
|
:returns: number of fresh messages
|
||||||
"""
|
"""
|
||||||
return lib.dc_get_fresh_msg_cnt(self.dc_context, self.id)
|
return lib.dc_get_fresh_msg_cnt(self._dc_context.p, self.id)
|
||||||
|
|
||||||
def mark_noticed(self):
|
def mark_noticed(self):
|
||||||
""" mark all messages in this chat as noticed.
|
""" mark all messages in this chat as noticed.
|
||||||
|
|
||||||
Noticed messages are no longer fresh.
|
Noticed messages are no longer fresh.
|
||||||
"""
|
"""
|
||||||
return lib.dc_marknoticed_chat(self.dc_context, self.id)
|
return lib.dc_marknoticed_chat(self._dc_context.p, self.id)
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
|
@ -107,21 +97,18 @@ class Message(object):
|
||||||
You obtain instances of it through :class:`deltachat.account.Account` or
|
You obtain instances of it through :class:`deltachat.account.Account` or
|
||||||
:class:`Chat`.
|
:class:`Chat`.
|
||||||
"""
|
"""
|
||||||
dc_context = attr.ib(validator=v.instance_of(ffi.CData))
|
_dc_context = attr.ib(validator=v.instance_of(DC_Context))
|
||||||
id = attr.ib(validator=v.instance_of(int))
|
id = attr.ib(validator=v.instance_of(int))
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def dc_msg_t(self):
|
def _dc_msg(self):
|
||||||
return capi.lib.dc_get_msg(self.dc_context, self.id)
|
return DC_Msg(lib.dc_get_msg(self._dc_context.p, self.id))
|
||||||
|
|
||||||
def _refresh(self):
|
def _refresh(self):
|
||||||
if hasattr(self, "_property_cache"):
|
try:
|
||||||
lib.dc_msg_unref(self.dc_msg_t)
|
del self._dc_msg
|
||||||
self._property_cache.clear()
|
except KeyError:
|
||||||
|
pass
|
||||||
def __del__(self):
|
|
||||||
if lib is not None and hasattr(self, "_property_cache"):
|
|
||||||
lib.dc_msg_unref(self.dc_msg_t)
|
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
""" get the message in/out state.
|
""" get the message in/out state.
|
||||||
|
@ -133,7 +120,7 @@ class Message(object):
|
||||||
@property_with_doc
|
@property_with_doc
|
||||||
def text(self):
|
def text(self):
|
||||||
"""unicode representation. """
|
"""unicode representation. """
|
||||||
return ffi_unicode(capi.lib.dc_msg_get_text(self.dc_msg_t))
|
return ffi_unicode(lib.dc_msg_get_text(self._dc_msg.p))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def chat(self):
|
def chat(self):
|
||||||
|
@ -141,8 +128,8 @@ class Message(object):
|
||||||
|
|
||||||
:returns: :class:`Chat` object
|
:returns: :class:`Chat` object
|
||||||
"""
|
"""
|
||||||
chat_id = capi.lib.dc_msg_get_chat_id(self.dc_msg_t)
|
chat_id = lib.dc_msg_get_chat_id(self._dc_msg.p)
|
||||||
return Chat(self.dc_context, chat_id)
|
return Chat(self._dc_context, chat_id)
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
|
@ -154,7 +141,7 @@ class MessageState(object):
|
||||||
@property
|
@property
|
||||||
def _msgstate(self):
|
def _msgstate(self):
|
||||||
self.message._refresh()
|
self.message._refresh()
|
||||||
return lib.dc_msg_get_state(self.message.dc_msg_t)
|
return lib.dc_msg_get_state(self.message._dc_msg.p)
|
||||||
|
|
||||||
def is_in_fresh(self):
|
def is_in_fresh(self):
|
||||||
""" return True if Message is incoming fresh message (un-noticed).
|
""" return True if Message is incoming fresh message (un-noticed).
|
||||||
|
|
|
@ -1,9 +1,36 @@
|
||||||
|
from .capi import lib
|
||||||
|
|
||||||
|
|
||||||
def property_with_doc(f):
|
def property_with_doc(f):
|
||||||
return property(f, None, None, f.__doc__)
|
return property(f, None, None, f.__doc__)
|
||||||
|
|
||||||
|
|
||||||
|
class _UnrefStruct(object):
|
||||||
|
def __init__(self, c_obj):
|
||||||
|
self.p = c_obj
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
obj = self.__dict__.pop("p", None)
|
||||||
|
if lib is not None and obj is not None:
|
||||||
|
self._unref(obj)
|
||||||
|
|
||||||
|
|
||||||
|
class DC_Context(_UnrefStruct):
|
||||||
|
_unref = lib.dc_context_unref
|
||||||
|
|
||||||
|
|
||||||
|
class DC_Contact(_UnrefStruct):
|
||||||
|
_unref = lib.dc_contact_unref
|
||||||
|
|
||||||
|
|
||||||
|
class DC_Chat(_UnrefStruct):
|
||||||
|
_unref = lib.dc_chat_unref
|
||||||
|
|
||||||
|
|
||||||
|
class DC_Msg(_UnrefStruct):
|
||||||
|
_unref = lib.dc_msg_unref
|
||||||
|
|
||||||
|
|
||||||
# copied over unmodified from
|
# copied over unmodified from
|
||||||
# https://github.com/devpi/devpi/blob/master/common/devpi_common/types.py
|
# https://github.com/devpi/devpi/blob/master/common/devpi_common/types.py
|
||||||
|
|
||||||
|
@ -22,4 +49,9 @@ def cached_property(f):
|
||||||
def set(self, val):
|
def set(self, val):
|
||||||
propcache = self.__dict__.setdefault("_property_cache", {})
|
propcache = self.__dict__.setdefault("_property_cache", {})
|
||||||
propcache[f] = val
|
propcache[f] = val
|
||||||
return property(get, set)
|
|
||||||
|
def fdel(self):
|
||||||
|
propcache = self.__dict__.setdefault("_property_cache", {})
|
||||||
|
del propcache[f]
|
||||||
|
|
||||||
|
return property(get, set, fdel)
|
||||||
|
|
|
@ -48,7 +48,6 @@ class TestOfflineAccount:
|
||||||
assert chat2.id == chat.id
|
assert chat2.id == chat.id
|
||||||
assert chat == chat2
|
assert chat == chat2
|
||||||
assert not (chat != chat2)
|
assert not (chat != chat2)
|
||||||
assert chat.dc_chat_t
|
|
||||||
|
|
||||||
def test_message(self, acfactory):
|
def test_message(self, acfactory):
|
||||||
ac1 = acfactory.get_offline_account()
|
ac1 = acfactory.get_offline_account()
|
||||||
|
@ -77,14 +76,14 @@ class TestOnlineAccount:
|
||||||
imap_ok = True
|
imap_ok = True
|
||||||
if evt_name == "DC_EVENT_SMTP_CONNECTED":
|
if evt_name == "DC_EVENT_SMTP_CONNECTED":
|
||||||
smtp_ok = True
|
smtp_ok = True
|
||||||
print("** IMAP and SMTP logins successful", account.dc_context)
|
print("** IMAP and SMTP logins successful", account)
|
||||||
|
|
||||||
def wait_configuration_progress(self, account, target):
|
def wait_configuration_progress(self, account, target):
|
||||||
while 1:
|
while 1:
|
||||||
evt_name, data1, data2 = \
|
evt_name, data1, data2 = \
|
||||||
account._evlogger.get_matching("DC_EVENT_CONFIGURE_PROGRESS")
|
account._evlogger.get_matching("DC_EVENT_CONFIGURE_PROGRESS")
|
||||||
if data1 >= target:
|
if data1 >= target:
|
||||||
print("** CONFIG PROGRESS {}".format(target), account.dc_context)
|
print("** CONFIG PROGRESS {}".format(target), account)
|
||||||
break
|
break
|
||||||
|
|
||||||
def test_selfcontact(self, acfactory):
|
def test_selfcontact(self, acfactory):
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from deltachat import capi
|
import pytest
|
||||||
|
from deltachat import capi, Account
|
||||||
|
|
||||||
|
|
||||||
def test_empty_context():
|
def test_empty_context():
|
||||||
|
@ -7,6 +8,12 @@ def test_empty_context():
|
||||||
capi.lib.dc_close(ctx)
|
capi.lib.dc_close(ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def test_wrong_db(tmpdir):
|
||||||
|
tmpdir.join("hello.db").write("123")
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Account(db_path=tmpdir.strpath)
|
||||||
|
|
||||||
|
|
||||||
def test_event_defines():
|
def test_event_defines():
|
||||||
assert capi.lib.DC_EVENT_INFO == 100
|
assert capi.lib.DC_EVENT_INFO == 100
|
||||||
assert capi.lib.DC_CONTACT_ID_SELF
|
assert capi.lib.DC_CONTACT_ID_SELF
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue