Implement Message(), Database.find_message(), Database.create()
authorSebastian Spaeth <sebastian@sspaeth.de>
Tue, 16 Mar 2010 10:27:31 +0000 (11:27 +0100)
committerSebastian Spaeth <sebastian@sspaeth.de>
Tue, 16 Mar 2010 10:27:31 +0000 (11:27 +0100)
Message() basically has get_message_id get_filename get_tags
Plus various bullet proofing and bug fixing.

--HG--
extra : transplant_source : O%3B1%EB%E0%D4pYrEY_%E3%0E%BA%C23%11a%B0

cnotmuch/database.py
cnotmuch/globals.py

index 2df3b4cbc37547e153fbee1f4f9db4ee9d078a8c..10251c42f3b6918f106d3d90bf5e886d41a84fea 100644 (file)
@@ -24,47 +24,57 @@ class Database(object):
     _open = nmlib.notmuch_database_open 
     _open.restype = c_void_p
 
+    """ notmuch_database_find_message """
+    _find_message = nmlib.notmuch_database_find_message
+    _find_message.restype = c_void_p
+
     """notmuch_database_get_all_tags (notmuch_database_t *database)"""
     _get_all_tags = nmlib.notmuch_database_get_all_tags
     _get_all_tags.restype = c_void_p
 
-    class notmuch_database_t(ctypes.Structure):
-        """the opaque database that is returned by functions."""
-        pass
+    """ notmuch_database_create(const char *path):"""
+    _create = nmlib.notmuch_database_create
+    _create.restype = c_void_p
 
     def __init__(self, path=None, create=False, status= MODE_READ_ONLY):
-        """ Open or create a notmuch database"""
+        """ Open or create a notmuch database
+
+        If path is None, we will try to read a users notmuch configuration and
+        use his default database.
+        Throws a NotmuchError in case of failure.
+        """
         self._db = None
+        if path is None:
+            # no path specified. use a user's default database
+            if Database._std_db_path is None:
+                #the following line throws a NotmuchError if it fails
+                Database._std_db_path = self._get_user_default_db()
+            path = Database._std_db_path
+
         if create == False:
             self.open(path, status)
         else:
-            #TODO: implement
-            raise NotmuchError(message="Not implemented yet")
+            self.create(path, status)
 
-    #TODO: make a proper function
-    create=nmlib.notmuch_database_create
-    """ notmuch_database_create(const char *path):"""
+    def create(self, path, status=MODE_READ_ONLY):
+        """ notmuch_database_create(const char *path)
+
+        :returns: Raises :exc:`notmuch.NotmuchError` in case
+                  of any failure (after printing an error message on stderr).
+        """
+        res = Database._create(path, status)
 
-    def open(self, path=None, status= MODE_READ_ONLY): 
+        if res is None:
+            raise NotmuchError(
+                message="Could not create the specified database")
+        self._db = res
+
+    def open(self, path, status= MODE_READ_ONLY): 
         """calls notmuch_database_open
 
-        If path is None, we will try to read a users notmuch configuration and
-        use his default database.
         :returns: Raises :exc:`notmuch.NotmuchError` in case
                   of any failure (after printing an error message on stderr).
         """
-        if path is None:
-            if Database._std_db_path is None:
-                from ConfigParser import SafeConfigParser
-                import os.path
-                config = SafeConfigParser()
-                config.read(os.path.expanduser('~/.notmuch-config'))
-                if not config.has_option('database','path'):
-                    raise NotmuchError(message=
-                              "No DB path specified and no user default found")
-                Database._std_db_path=config.get('database','path')
-            path = Database._std_db_path
-
         res = Database._open(path, status)
 
         if res is None:
@@ -76,12 +86,20 @@ class Database(object):
         """notmuch_database_get_path (notmuch_database_t *database);  """
         return Database._get_path(self._db)
 
-    #TODO:implement
-    #If no message is found with the given message_id or if an
-    #out-of-memory situation occurs, this function returns NULL.
-    #notmuch_message_t *
-    #notmuch_database_find_message (notmuch_database_t *database,
-    #                               const char *message_id);
+    def find_message(self, msgid):
+        """notmuch_database_find_message
+        :param msgid: The message id
+        :ptype msgid: string
+
+        :returns: Message() or None if no message is found or if an
+                  out-of-memory situation occurs.
+        """
+        if self._db is None:
+            raise NotmuchError(STATUS.NOT_INITIALIZED)
+        msg_p = Database._find_message(self._db, msgid)
+        if msg_p is None:
+            return None
+        return Message(msg_p, self)
 
     def get_all_tags(self):
         """Return a Tags() object (list of all tags found in the database)
@@ -89,6 +107,9 @@ class Database(object):
         :returns: Tags() object or raises :exc:`NotmuchError` with 
                   STATUS.NULL_POINTER on error
         """
+        if self._db is None:
+            raise NotmuchError(STATUS.NOT_INITIALIZED)
+
         tags_p = Database._get_all_tags (self._db)
         if tags_p == None:
             raise NotmuchError(STATUS.NULL_POINTER)
@@ -103,6 +124,19 @@ class Database(object):
             print("Freeing the database now")
             nmlib.notmuch_database_close(self._db)
 
+    def _get_user_default_db(self):
+        """ Reads a user's notmuch config and returns his db location
+
+        Throws a NotmuchError if it cannot find it"""
+        from ConfigParser import SafeConfigParser
+        import os.path
+        config = SafeConfigParser()
+        config.read(os.path.expanduser('~/.notmuch-config'))
+        if not config.has_option('database','path'):
+            raise NotmuchError(message=
+                               "No DB path specified and no user default found")
+        return config.get('database','path')
+
     @property
     def db_p(self):
         """Returns a pointer to the current notmuch_database_t or None"""
@@ -121,7 +155,11 @@ class Tags(object):
     _get.restype = c_char_p
 
     def __init__(self, tags_p, db=None):
-        """ Is passed the db these tags are derived from, and saves a
+        """
+        msg_p is a pointer to an notmuch_message_t Structure. If it is None,
+        we will raise an NotmuchError(STATUS.NULL_POINTER).
+
+        Is passed the db these tags are derived from, and saves a
         reference to it, so we can automatically delete the db object
         once all derived objects are dead.
 
@@ -131,9 +169,12 @@ class Tags(object):
         #TODO: make the iterator work more than once and cache the tags in 
                the Python object.
         """
+        if tags_p is None:
+            NotmuchError(STATUS.NULL_POINTER)
+
         self._tags = tags_p
         self._db = db
-        print "inited tags with %d %s" %(tags_p, str(db))
+        print "Inited Tags derived from %s" %(str(db))
     
     def __iter__(self):
         """ Make Tags an iterator """
@@ -154,3 +195,73 @@ class Tags(object):
         if self._tags is not None:
             print("Freeing the Tags now")
             nmlib.notmuch_tags_destroy (self._tags)
+
+#------------------------------------------------------------------------------
+class Message(object):
+    """Wrapper around notmuch_message_t"""
+
+    """notmuch_message_get_filename (notmuch_message_t *message)"""
+    _get_filename = nmlib.notmuch_message_get_filename
+    _get_filename.restype = c_char_p 
+    """notmuch_message_get_message_id (notmuch_message_t *message)"""
+    _get_message_id = nmlib.notmuch_message_get_message_id
+    _get_message_id.restype = c_char_p 
+
+    """notmuch_message_get_tags (notmuch_message_t *message)"""
+    _get_tags = nmlib.notmuch_message_get_tags
+    _get_tags.restype = c_void_p
+
+    def __init__(self, msg_p, parent=None):
+        """
+        msg_p is a pointer to an notmuch_message_t Structure. If it is None,
+        we will raise an NotmuchError(STATUS.NULL_POINTER).
+
+        Is a 'parent' object is passed which this message is derived from,
+        we save a reference to it, so we can automatically delete the parent
+        object once all derived objects are dead.
+        """
+        if msg_p is None:
+            NotmuchError(STATUS.NULL_POINTER)
+        self._msg = msg_p
+        self._parent = parent
+        print "Inited Message derived from %s" %(str(parent))
+
+
+    def get_message_id(self):
+        """ return the msg id
+        
+        Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
+        """
+        if self._msg is None:
+            raise NotmuchError(STATUS.NOT_INITIALIZED)
+        return Message._get_message_id(self._msg)
+
+
+    def get_filename(self):
+        """ return the msg filename
+        
+        Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
+        """
+        if self._msg is None:
+            raise NotmuchError(STATUS.NOT_INITIALIZED)
+        return Message._get_filename(self._msg)
+
+    def get_tags(self):
+        """ return the msg tags
+        
+        Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
+        Raises NotmuchError(STATUS.NULL_POINTER) on error.
+        """
+        if self._msg is None:
+            raise NotmuchError(STATUS.NOT_INITIALIZED)
+
+        tags_p = Message._get_tags(self._msg)
+        if tags_p == None:
+            raise NotmuchError(STATUS.NULL_POINTER)
+        return Tags(tags_p, self)
+
+    def __del__(self):
+        """Close and free the notmuch Message"""
+        if self._msg is not None:
+            print("Freeing the Message now")
+            nmlib.notmuch_message_destroy (self._msg)
index ff765167a7974ec0bd0ade1c102e128fbe920533..553670a49c5c1460a1c77c24ff3b144e5cf2a05a 100644 (file)
@@ -14,7 +14,7 @@ class STATUS(object):
   NULL_POINTER = 7
   TAG_TOO_LONG = 8
   UNBALANCED_FREEZE_THAW = 9
-  LAST_STATUS = 10
+  NOT_INITIALIZED = 10
 
   """Get a string representation of a notmuch_status_t value."""
   status2str = nmlib.notmuch_status_to_string
@@ -26,6 +26,9 @@ class STATUS(object):
 
   def __str__(self):
       """Get a string representation of a notmuch_status_t value."""   
+      # define strings for custom error messages
+      if self._status == STATUS.NOT_INITIALIZED:
+        return "Operation on uninitialized DB/MSG/THREAD impossible."
       return str(STATUS.status2str(self._status))
 
 class NotmuchError(Exception):