aboutsummaryrefslogtreecommitdiffhomepage
path: root/bindings
diff options
context:
space:
mode:
authorGravatar Justus Winter <4winter@informatik.uni-hamburg.de>2012-02-22 21:55:59 +0100
committerGravatar Justus Winter <4winter@informatik.uni-hamburg.de>2012-02-22 22:06:45 +0100
commitba95980cf1a5e2b32104611ccdf2e9c43bf3305a (patch)
tree790bd53661dbe6818032df0929ce1369fcb478bc /bindings
parent1736488ecfd9b18a380ce04ac2df0303c0ea3c80 (diff)
python: refactor the python bindings
Move the Directory class into its own file, merge the two Filenames classes into one, deprecate Filenames.as_iterator, update the documentation accordingly. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
Diffstat (limited to 'bindings')
-rw-r--r--bindings/python/docs/source/index.rst20
-rw-r--r--bindings/python/notmuch/__init__.py15
-rw-r--r--bindings/python/notmuch/database.py239
-rw-r--r--bindings/python/notmuch/directory.py183
-rw-r--r--bindings/python/notmuch/filename.py62
5 files changed, 256 insertions, 263 deletions
diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst
index 25eb146c..e87a8659 100644
--- a/bindings/python/docs/source/index.rst
+++ b/bindings/python/docs/source/index.rst
@@ -254,26 +254,28 @@ More information on specific topics can be found on the following pages:
:class:`Filenames` -- An iterator over filenames
------------------------------------------------
-.. autoclass:: notmuch.database.Filenames
+.. autoclass:: notmuch.Filenames
- .. automethod:: notmuch.database.Filenames.__len__
+ .. automethod:: notmuch.Filenames.__len__
+
+ .. automethod:: notmuch.Filenames.as_generator
:class:`notmuch.database.Directoy` -- A directory entry in the database
------------------------------------------------------------------------
-.. autoclass:: notmuch.database.Directory
+.. autoclass:: notmuch.Directory
- .. automethod:: notmuch.database.Directory.get_child_files
+ .. automethod:: notmuch.Directory.get_child_files
- .. automethod:: notmuch.database.Directory.get_child_directories
+ .. automethod:: notmuch.Directory.get_child_directories
- .. automethod:: notmuch.database.Directory.get_mtime
+ .. automethod:: notmuch.Directory.get_mtime
- .. automethod:: notmuch.database.Directory.set_mtime
+ .. automethod:: notmuch.Directory.set_mtime
- .. autoattribute:: notmuch.database.Directory.mtime
+ .. autoattribute:: notmuch.Directory.mtime
- .. autoattribute:: notmuch.database.Directory.path
+ .. autoattribute:: notmuch.Directory.path
The `next page <status_and_errors.html>`_ contains information on possible Status and Error values.
diff --git a/bindings/python/notmuch/__init__.py b/bindings/python/notmuch/__init__.py
index f3ff9874..8de73d58 100644
--- a/bindings/python/notmuch/__init__.py
+++ b/bindings/python/notmuch/__init__.py
@@ -51,11 +51,14 @@ along with notmuch. If not, see <http://www.gnu.org/licenses/>.
Copyright 2010-2011 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""
-from notmuch.database import Database, Query
-from notmuch.message import Messages, Message
-from notmuch.thread import Threads, Thread
-from notmuch.tag import Tags
-from notmuch.globals import (
+from .database import Database
+from .directory import Directory
+from .filename import Filenames
+from .message import Messages, Message
+from .query import Query
+from .tag import Tags
+from .thread import Threads, Thread
+from .globals import (
nmlib,
STATUS,
NotmuchError,
@@ -71,6 +74,6 @@ from notmuch.globals import (
UnbalancedAtomicError,
NotInitializedError,
)
-from notmuch.version import __VERSION__
+from .version import __VERSION__
__LICENSE__ = "GPL v3+"
__AUTHOR__ = 'Sebastian Spaeth <Sebastian@SSpaeth.de>'
diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index a054be76..800264b7 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -19,7 +19,7 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
import os
import codecs
-from ctypes import c_char_p, c_void_p, c_uint, c_long, byref, POINTER
+from ctypes import c_char_p, c_void_p, c_uint, byref, POINTER
from notmuch.globals import (
nmlib,
STATUS,
@@ -34,11 +34,11 @@ from notmuch.globals import (
NotmuchDirectoryP,
NotmuchMessageP,
NotmuchTagsP,
- NotmuchFilenamesP
)
from notmuch.message import Message
from notmuch.tag import Tags
from .query import Query
+from .directory import Directory
class Database(object):
"""The :class:`Database` is the highest-level object that notmuch
@@ -603,238 +603,3 @@ class Database(object):
guaranteed to remain stable in future versions).
"""
return self._db
-
-
-class Directory(object):
- """Represents a directory entry in the notmuch directory
-
- Modifying attributes of this object will modify the
- database, not the real directory attributes.
-
- The Directory object is usually derived from another object
- e.g. via :meth:`Database.get_directory`, and will automatically be
- become invalid whenever that parent is deleted. You should
- therefore initialized this object handing it a reference to the
- parent, preventing the parent from automatically being garbage
- collected.
- """
-
- """notmuch_directory_get_mtime"""
- _get_mtime = nmlib.notmuch_directory_get_mtime
- _get_mtime.argtypes = [NotmuchDirectoryP]
- _get_mtime.restype = c_long
-
- """notmuch_directory_set_mtime"""
- _set_mtime = nmlib.notmuch_directory_set_mtime
- _set_mtime.argtypes = [NotmuchDirectoryP, c_long]
- _set_mtime.restype = c_uint
-
- """notmuch_directory_get_child_files"""
- _get_child_files = nmlib.notmuch_directory_get_child_files
- _get_child_files.argtypes = [NotmuchDirectoryP]
- _get_child_files.restype = NotmuchFilenamesP
-
- """notmuch_directory_get_child_directories"""
- _get_child_directories = nmlib.notmuch_directory_get_child_directories
- _get_child_directories.argtypes = [NotmuchDirectoryP]
- _get_child_directories.restype = NotmuchFilenamesP
-
- def _assert_dir_is_initialized(self):
- """Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED)
- if dir_p is None"""
- if not self._dir_p:
- raise NotInitializedError()
-
- def __init__(self, path, dir_p, parent):
- """
- :param path: The absolute path of the directory object.
- :param dir_p: The pointer to an internal notmuch_directory_t object.
- :param parent: The object this Directory is derived from
- (usually a :class:`Database`). We do not directly use
- this, but store a reference to it as long as
- this Directory object lives. This keeps the
- parent object alive.
- """
- self._path = path
- self._dir_p = dir_p
- self._parent = parent
-
- def set_mtime(self, mtime):
- """Sets the mtime value of this directory in the database
-
- The intention is for the caller to use the mtime to allow efficient
- identification of new messages to be added to the database. The
- recommended usage is as follows:
-
- * Read the mtime of a directory from the filesystem
-
- * Call :meth:`Database.add_message` for all mail files in
- the directory
-
- * Call notmuch_directory_set_mtime with the mtime read from the
- filesystem. Then, when wanting to check for updates to the
- directory in the future, the client can call :meth:`get_mtime`
- and know that it only needs to add files if the mtime of the
- directory and files are newer than the stored timestamp.
-
- .. note::
-
- :meth:`get_mtime` function does not allow the caller to
- distinguish a timestamp of 0 from a non-existent timestamp. So
- don't store a timestamp of 0 unless you are comfortable with
- that.
-
- :param mtime: A (time_t) timestamp
- :raises: :exc:`XapianError` a Xapian exception occurred, mtime
- not stored
- :raises: :exc:`ReadOnlyDatabaseError` the database was opened
- in read-only mode so directory mtime cannot be modified
- :raises: :exc:`NotInitializedError` the directory object has not
- been initialized
- """
- self._assert_dir_is_initialized()
- status = Directory._set_mtime(self._dir_p, mtime)
-
- if status != STATUS.SUCCESS:
- raise NotmuchError(status)
-
- def get_mtime(self):
- """Gets the mtime value of this directory in the database
-
- Retrieves a previously stored mtime for this directory.
-
- :param mtime: A (time_t) timestamp
- :raises: :exc:`NotmuchError`:
-
- :attr:`STATUS`.NOT_INITIALIZED
- The directory has not been initialized
- """
- self._assert_dir_is_initialized()
- return Directory._get_mtime(self._dir_p)
-
- # Make mtime attribute a property of Directory()
- mtime = property(get_mtime, set_mtime, doc="""Property that allows getting
- and setting of the Directory *mtime* (read-write)
-
- See :meth:`get_mtime` and :meth:`set_mtime` for usage and
- possible exceptions.""")
-
- def get_child_files(self):
- """Gets a Filenames iterator listing all the filenames of
- messages in the database within the given directory.
-
- The returned filenames will be the basename-entries only (not
- complete paths.
- """
- self._assert_dir_is_initialized()
- files_p = Directory._get_child_files(self._dir_p)
- return Filenames(files_p, self)
-
- def get_child_directories(self):
- """Gets a :class:`Filenames` iterator listing all the filenames of
- sub-directories in the database within the given directory
-
- The returned filenames will be the basename-entries only (not
- complete paths.
- """
- self._assert_dir_is_initialized()
- files_p = Directory._get_child_directories(self._dir_p)
- return Filenames(files_p, self)
-
- @property
- def path(self):
- """Returns the absolute path of this Directory (read-only)"""
- return self._path
-
- def __repr__(self):
- """Object representation"""
- return "<notmuch Directory object '%s'>" % self._path
-
- _destroy = nmlib.notmuch_directory_destroy
- _destroy.argtypes = [NotmuchDirectoryP]
- _destroy.argtypes = None
-
- def __del__(self):
- """Close and free the Directory"""
- if self._dir_p is not None:
- self._destroy(self._dir_p)
-
-
-class Filenames(object):
- """An iterator over File- or Directory names stored in the database"""
-
- #notmuch_filenames_get
- _get = nmlib.notmuch_filenames_get
- _get.argtypes = [NotmuchFilenamesP]
- _get.restype = c_char_p
-
- def __init__(self, files_p, parent):
- """
- :param files_p: The pointer to an internal notmuch_filenames_t object.
- :param parent: The object this Directory is derived from
- (usually a Directory()). We do not directly use
- this, but store a reference to it as long as
- this Directory object lives. This keeps the
- parent object alive.
- """
- self._files_p = files_p
- self._parent = parent
-
- def __iter__(self):
- """ Make Filenames an iterator """
- return self
-
- _valid = nmlib.notmuch_filenames_valid
- _valid.argtypes = [NotmuchFilenamesP]
- _valid.restype = bool
-
- _move_to_next = nmlib.notmuch_filenames_move_to_next
- _move_to_next.argtypes = [NotmuchFilenamesP]
- _move_to_next.restype = None
-
- def __next__(self):
- if not self._files_p:
- raise NotInitializedError()
-
- if not self._valid(self._files_p):
- self._files_p = None
- raise StopIteration
-
- file_ = Filenames._get(self._files_p)
- self._move_to_next(self._files_p)
- return file_.decode('utf-8', 'ignore')
- next = __next__ # python2.x iterator protocol compatibility
-
- def __len__(self):
- """len(:class:`Filenames`) returns the number of contained files
-
- .. note::
-
- As this iterates over the files, we will not be able to
- iterate over them again! So this will fail::
-
- #THIS FAILS
- files = Database().get_directory('').get_child_files()
- if len(files) > 0: # this 'exhausts' msgs
- # next line raises
- # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED)
- for file in files: print file
- """
- if not self._files_p:
- raise NotInitializedError()
-
- i = 0
- while self._valid(self._files_p):
- self._move_to_next(self._files_p)
- i += 1
- self._files_p = None
- return i
-
- _destroy = nmlib.notmuch_filenames_destroy
- _destroy.argtypes = [NotmuchFilenamesP]
- _destroy.restype = None
-
- def __del__(self):
- """Close and free Filenames"""
- if self._files_p is not None:
- self._destroy(self._files_p)
diff --git a/bindings/python/notmuch/directory.py b/bindings/python/notmuch/directory.py
new file mode 100644
index 00000000..3e0763f2
--- /dev/null
+++ b/bindings/python/notmuch/directory.py
@@ -0,0 +1,183 @@
+"""
+This file is part of notmuch.
+
+Notmuch is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Notmuch is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with notmuch. If not, see <http://www.gnu.org/licenses/>.
+
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+"""
+
+from ctypes import c_uint, c_long
+from notmuch.globals import (
+ nmlib,
+ STATUS,
+ NotmuchError,
+ NotInitializedError,
+ NotmuchDirectoryP,
+ NotmuchFilenamesP
+)
+from .filename import Filenames
+
+class Directory(object):
+ """Represents a directory entry in the notmuch directory
+
+ Modifying attributes of this object will modify the
+ database, not the real directory attributes.
+
+ The Directory object is usually derived from another object
+ e.g. via :meth:`Database.get_directory`, and will automatically be
+ become invalid whenever that parent is deleted. You should
+ therefore initialized this object handing it a reference to the
+ parent, preventing the parent from automatically being garbage
+ collected.
+ """
+
+ """notmuch_directory_get_mtime"""
+ _get_mtime = nmlib.notmuch_directory_get_mtime
+ _get_mtime.argtypes = [NotmuchDirectoryP]
+ _get_mtime.restype = c_long
+
+ """notmuch_directory_set_mtime"""
+ _set_mtime = nmlib.notmuch_directory_set_mtime
+ _set_mtime.argtypes = [NotmuchDirectoryP, c_long]
+ _set_mtime.restype = c_uint
+
+ """notmuch_directory_get_child_files"""
+ _get_child_files = nmlib.notmuch_directory_get_child_files
+ _get_child_files.argtypes = [NotmuchDirectoryP]
+ _get_child_files.restype = NotmuchFilenamesP
+
+ """notmuch_directory_get_child_directories"""
+ _get_child_directories = nmlib.notmuch_directory_get_child_directories
+ _get_child_directories.argtypes = [NotmuchDirectoryP]
+ _get_child_directories.restype = NotmuchFilenamesP
+
+ def _assert_dir_is_initialized(self):
+ """Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED)
+ if dir_p is None"""
+ if not self._dir_p:
+ raise NotInitializedError()
+
+ def __init__(self, path, dir_p, parent):
+ """
+ :param path: The absolute path of the directory object.
+ :param dir_p: The pointer to an internal notmuch_directory_t object.
+ :param parent: The object this Directory is derived from
+ (usually a :class:`Database`). We do not directly use
+ this, but store a reference to it as long as
+ this Directory object lives. This keeps the
+ parent object alive.
+ """
+ self._path = path
+ self._dir_p = dir_p
+ self._parent = parent
+
+ def set_mtime(self, mtime):
+ """Sets the mtime value of this directory in the database
+
+ The intention is for the caller to use the mtime to allow efficient
+ identification of new messages to be added to the database. The
+ recommended usage is as follows:
+
+ * Read the mtime of a directory from the filesystem
+
+ * Call :meth:`Database.add_message` for all mail files in
+ the directory
+
+ * Call notmuch_directory_set_mtime with the mtime read from the
+ filesystem. Then, when wanting to check for updates to the
+ directory in the future, the client can call :meth:`get_mtime`
+ and know that it only needs to add files if the mtime of the
+ directory and files are newer than the stored timestamp.
+
+ .. note::
+
+ :meth:`get_mtime` function does not allow the caller to
+ distinguish a timestamp of 0 from a non-existent timestamp. So
+ don't store a timestamp of 0 unless you are comfortable with
+ that.
+
+ :param mtime: A (time_t) timestamp
+ :raises: :exc:`XapianError` a Xapian exception occurred, mtime
+ not stored
+ :raises: :exc:`ReadOnlyDatabaseError` the database was opened
+ in read-only mode so directory mtime cannot be modified
+ :raises: :exc:`NotInitializedError` the directory object has not
+ been initialized
+ """
+ self._assert_dir_is_initialized()
+ status = Directory._set_mtime(self._dir_p, mtime)
+
+ if status != STATUS.SUCCESS:
+ raise NotmuchError(status)
+
+ def get_mtime(self):
+ """Gets the mtime value of this directory in the database
+
+ Retrieves a previously stored mtime for this directory.
+
+ :param mtime: A (time_t) timestamp
+ :raises: :exc:`NotmuchError`:
+
+ :attr:`STATUS`.NOT_INITIALIZED
+ The directory has not been initialized
+ """
+ self._assert_dir_is_initialized()
+ return Directory._get_mtime(self._dir_p)
+
+ # Make mtime attribute a property of Directory()
+ mtime = property(get_mtime, set_mtime, doc="""Property that allows getting
+ and setting of the Directory *mtime* (read-write)
+
+ See :meth:`get_mtime` and :meth:`set_mtime` for usage and
+ possible exceptions.""")
+
+ def get_child_files(self):
+ """Gets a Filenames iterator listing all the filenames of
+ messages in the database within the given directory.
+
+ The returned filenames will be the basename-entries only (not
+ complete paths.
+ """
+ self._assert_dir_is_initialized()
+ files_p = Directory._get_child_files(self._dir_p)
+ return Filenames(files_p, self)
+
+ def get_child_directories(self):
+ """Gets a :class:`Filenames` iterator listing all the filenames of
+ sub-directories in the database within the given directory
+
+ The returned filenames will be the basename-entries only (not
+ complete paths.
+ """
+ self._assert_dir_is_initialized()
+ files_p = Directory._get_child_directories(self._dir_p)
+ return Filenames(files_p, self)
+
+ @property
+ def path(self):
+ """Returns the absolute path of this Directory (read-only)"""
+ return self._path
+
+ def __repr__(self):
+ """Object representation"""
+ return "<notmuch Directory object '%s'>" % self._path
+
+ _destroy = nmlib.notmuch_directory_destroy
+ _destroy.argtypes = [NotmuchDirectoryP]
+ _destroy.argtypes = None
+
+ def __del__(self):
+ """Close and free the Directory"""
+ if self._dir_p is not None:
+ self._destroy(self._dir_p)
diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py
index 353eb76e..232a9eda 100644
--- a/bindings/python/notmuch/filename.py
+++ b/bindings/python/notmuch/filename.py
@@ -78,10 +78,14 @@ class Filenames(Python3StringMixIn):
if not files_p:
raise NullPointerError()
- self._files = files_p
+ self._files_p = files_p
#save reference to parent object so we keep it alive
self._parent = parent
+ def __iter__(self):
+ """ Make Filenames an iterator """
+ return self
+
_valid = nmlib.notmuch_filenames_valid
_valid.argtypes = [NotmuchFilenamesP]
_valid.restype = bool
@@ -90,19 +94,30 @@ class Filenames(Python3StringMixIn):
_move_to_next.argtypes = [NotmuchFilenamesP]
_move_to_next.restype = None
+ def __next__(self):
+ if not self._files_p:
+ raise NotInitializedError()
+
+ if not self._valid(self._files_p):
+ self._files_p = None
+ raise StopIteration
+
+ file_ = Filenames._get(self._files_p)
+ self._move_to_next(self._files_p)
+ return file_.decode('utf-8', 'ignore')
+ next = __next__ # python2.x iterator protocol compatibility
+
def as_generator(self):
"""Return generator of Filenames
This is the main function that will usually be used by the
- user."""
- if not self._files:
- raise NotInitializedError()
+ user.
- while self._valid(self._files):
- yield Filenames._get(self._files).decode('utf-8', 'ignore')
- self._move_to_next(self._files)
-
- self._files = None
+ .. deprecated:: 0.12
+ :class:`Filenames` objects implement the
+ iterator protocol.
+ """
+ return self
def __unicode__(self):
"""Represent Filenames() as newline-separated list of full paths
@@ -123,5 +138,30 @@ class Filenames(Python3StringMixIn):
def __del__(self):
"""Close and free the notmuch filenames"""
- if self._files is not None:
- self._destroy(self._files)
+ if self._files_p is not None:
+ self._destroy(self._files_p)
+
+ def __len__(self):
+ """len(:class:`Filenames`) returns the number of contained files
+
+ .. note::
+
+ As this iterates over the files, we will not be able to
+ iterate over them again! So this will fail::
+
+ #THIS FAILS
+ files = Database().get_directory('').get_child_files()
+ if len(files) > 0: # this 'exhausts' msgs
+ # next line raises
+ # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED)
+ for file in files: print file
+ """
+ if not self._files_p:
+ raise NotInitializedError()
+
+ i = 0
+ while self._valid(self._files_p):
+ self._move_to_next(self._files_p)
+ i += 1
+ self._files_p = None
+ return i