[python] RFC: supporting python 2 and 3 with one codebase

classic Classic list List threaded Threaded
17 messages Options
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[python] RFC: supporting python 2 and 3 with one codebase

Hi everyone :)

attached is a patch series that makes the notmuch python bindings
compatible with both python 2.x and python 3.x.

There are some workarounds, but those are mostly in globals.py and in
my opinion the benefit of supporting both versions with one codebase
is totally worth it.

Patch seven adds missing unicode conversions that should be applied
even if the rest of the patchset is not.

Cheers,
Justus

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 1/7] py3k: The execfile built-in has been removed in python 3

---
 bindings/python/setup.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index 286fd19..2e58dab 100644
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -7,7 +7,7 @@ from distutils.core import setup
 # get the notmuch version number without importing the notmuch module
 version_file = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                             'notmuch', 'version.py')
-execfile(version_file)
+exec(compile(open(version_file).read(), version_file, 'exec'))
 assert __VERSION__, 'Failed to read the notmuch binding version number'
 
 setup(name='notmuch',
--
1.7.7.3

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 2/7] py3k: The ConfigParser module has been renamed to configparser

In reply to this post by Justus Winter
---
 bindings/python/notmuch.py          |    7 ++++++-
 bindings/python/notmuch/database.py |    8 +++++++-
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/bindings/python/notmuch.py b/bindings/python/notmuch.py
index 8d11859..3ff53ec 100755
--- a/bindings/python/notmuch.py
+++ b/bindings/python/notmuch.py
@@ -17,7 +17,12 @@ import stat
 import email
 
 from notmuch import Database, Query, NotmuchError, STATUS
-from ConfigParser import SafeConfigParser
+try:
+    # python3.x
+    from configparser import SafeConfigParser
+except ImportError:
+    # python2.x
+    from ConfigParser import SafeConfigParser
 from cStringIO import StringIO
 
 PREFIX = re.compile('(\w+):(.*$)')
diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index 7923f76..9318368 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -543,7 +543,13 @@ class Database(object):
         """ Reads a user's notmuch config and returns his db location
 
         Throws a NotmuchError if it cannot find it"""
-        from ConfigParser import SafeConfigParser
+        try:
+            # python3.x
+            from configparser import SafeConfigParser
+        except ImportError:
+            # python2.x
+            from ConfigParser import SafeConfigParser
+
         config = SafeConfigParser()
         conf_f = os.getenv('NOTMUCH_CONFIG',
                            os.path.expanduser('~/.notmuch-config'))
--
1.7.7.3

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 3/7] py3k: All strings are unicode strings in py3k

In reply to this post by Justus Winter
---
 bindings/python/notmuch/globals.py |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 54a49b2..99e6a10 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -51,7 +51,7 @@ class Status(Enum):
         """Get a (unicode) string representation of a notmuch_status_t value."""
         # define strings for custom error messages
         if status == STATUS.NOT_INITIALIZED:
-            return u"Operation on uninitialized object impossible."
+            return "Operation on uninitialized object impossible."
         return unicode(Status._status2str(status))
 
 STATUS = Status(['SUCCESS',
@@ -142,7 +142,7 @@ class NotmuchError(Exception):
         elif self.status is not None:
             return STATUS.status2str(self.status)
         else:
-            return u'Unknown error'
+            return 'Unknown error'
 
 
 # List of Subclassed exceptions that correspond to STATUS values and are
--
1.7.7.3

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 4/7] py3k: Rename .next() to __next__(), add python2.x compatibility alias

In reply to this post by Justus Winter
---
 bindings/python/notmuch/database.py |    3 ++-
 bindings/python/notmuch/message.py  |    3 ++-
 bindings/python/notmuch/tag.py      |    3 ++-
 bindings/python/notmuch/thread.py   |    3 ++-
 4 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index 9318368..3f6e04d 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -925,7 +925,7 @@ class Filenames(object):
     _move_to_next.argtypes = [NotmuchFilenamesP]
     _move_to_next.restype = None
 
-    def next(self):
+    def __next__(self):
         if self._files_p is None:
             raise NotmuchError(STATUS.NOT_INITIALIZED)
 
@@ -936,6 +936,7 @@ class Filenames(object):
         file = Filenames._get(self._files_p)
         self._move_to_next(self._files_p)
         return file
+    next = __next__ # python2.x iterator protocol compatibility
 
     def __len__(self):
         """len(:class:`Filenames`) returns the number of contained files
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index ce8e718..bf0c4da 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -158,7 +158,7 @@ class Messages(object):
     _move_to_next.argtypes = [NotmuchMessagesP]
     _move_to_next.restype = None
 
-    def next(self):
+    def __next__(self):
         if self._msgs is None:
             raise NotmuchError(STATUS.NOT_INITIALIZED)
 
@@ -169,6 +169,7 @@ class Messages(object):
         msg = Message(Messages._get(self._msgs), self)
         self._move_to_next(self._msgs)
         return msg
+    next = __next__ # python2.x iterator protocol compatibility
 
     def __nonzero__(self):
         """
diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py
index 2fb7d32..d42ba77 100644
--- a/bindings/python/notmuch/tag.py
+++ b/bindings/python/notmuch/tag.py
@@ -89,7 +89,7 @@ class Tags(object):
     _move_to_next.argtypes = [NotmuchTagsP]
     _move_to_next.restype = None
 
-    def next(self):
+    def __next__(self):
         if self._tags is None:
             raise NotmuchError(STATUS.NOT_INITIALIZED)
         if not self._valid(self._tags):
@@ -98,6 +98,7 @@ class Tags(object):
         tag = Tags._get(self._tags).decode('UTF-8')
         self._move_to_next(self._tags)
         return tag
+    next = __next__ # python2.x iterator protocol compatibility
 
     def __nonzero__(self):
         """Implement bool(Tags) check that can be repeatedly used
diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py
index 5058846..39285d6 100644
--- a/bindings/python/notmuch/thread.py
+++ b/bindings/python/notmuch/thread.py
@@ -116,7 +116,7 @@ class Threads(object):
     _move_to_next.argtypes = [NotmuchThreadsP]
     _move_to_next.restype = None
 
-    def next(self):
+    def __next__(self):
         if self._threads is None:
             raise NotmuchError(STATUS.NOT_INITIALIZED)
 
@@ -127,6 +127,7 @@ class Threads(object):
         thread = Thread(Threads._get(self._threads), self)
         self._move_to_next(self._threads)
         return thread
+    next = __next__ # python2.x iterator protocol compatibility
 
     def __len__(self):
         """len(:class:`Threads`) returns the number of contained Threads
--
1.7.7.3

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 5/7] py3k: the basestring and unicode types are removed in python 3

In reply to this post by Justus Winter
---
 bindings/python/notmuch/globals.py |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 99e6a10..c52790c 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -17,6 +17,7 @@ along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
 Copyright 2010 Sebastian Spaeth <[hidden email]>'
 """
 
+import sys
 from ctypes import CDLL, c_char_p, c_int, Structure, POINTER
 
 #-----------------------------------------------------------------------------
@@ -200,9 +201,9 @@ def _str(value):
 
     C++ code expects strings to be well formatted and
     unicode strings to have no null bytes."""
-    if not isinstance(value, basestring):
+    if not isinstance(value, basestring if sys.version_info[0] == 2 else str):
         raise TypeError("Expected str or unicode, got %s" % str(type(value)))
-    if isinstance(value, unicode):
+    if sys.version_info[0] == 3 or isinstance(value, unicode):
         return value.encode('UTF-8')
     return value
 
--
1.7.7.3

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 6/7] py3k: Add and use a mixin class that implements __str__

In reply to this post by Justus Winter
---
 bindings/python/notmuch/filename.py |    7 ++-----
 bindings/python/notmuch/globals.py  |   15 +++++++++++----
 bindings/python/notmuch/message.py  |    8 +++-----
 bindings/python/notmuch/tag.py      |    7 ++-----
 bindings/python/notmuch/thread.py   |    6 +++---
 5 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py
index a7cd7e6..969931a 100644
--- a/bindings/python/notmuch/filename.py
+++ b/bindings/python/notmuch/filename.py
@@ -18,10 +18,10 @@ Copyright 2010 Sebastian Spaeth <[hidden email]>'
 """
 from ctypes import c_char_p
 from notmuch.globals import (nmlib, STATUS, NotmuchError,
-    NotmuchFilenamesP, NotmuchMessageP)
+    NotmuchFilenamesP, NotmuchMessageP, _str, Python3StringMixIn)
 
 
-class Filenames(object):
+class Filenames(Python3StringMixIn):
     """Represents a list of filenames as returned by notmuch
 
     This object contains the Filenames iterator. The main function is
@@ -98,9 +98,6 @@ class Filenames(object):
 
         self._files = None
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
     def __unicode__(self):
         """Represent Filenames() as newline-separated list of full paths
 
diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index c52790c..2111b86 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -28,6 +28,16 @@ except:
     raise ImportError("Could not find shared 'notmuch' library.")
 
 
+if sys.version_info[0] == 2:
+    class Python3StringMixIn(object):
+        def __str__(self):
+            return unicode(self).encode('utf-8')
+else:
+    class Python3StringMixIn(object):
+        def __str__(self):
+            return self.__unicode__()
+
+
 class Enum(object):
     """Provides ENUMS as "code=Enum(['a','b','c'])" where code.a=0 etc..."""
     def __init__(self, names):
@@ -90,7 +100,7 @@ argument to receive a human readable string"""
 STATUS.__name__ = 'STATUS'
 
 
-class NotmuchError(Exception):
+class NotmuchError(Exception, Python3StringMixIn):
     """Is initiated with a (notmuch.STATUS[, message=None]). It will not
     return an instance of the class NotmuchError, but a derived instance
     of a more specific Error Message, e.g. OutOfMemoryError. Each status
@@ -134,9 +144,6 @@ class NotmuchError(Exception):
         self.status = status
         self.message = message
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
     def __unicode__(self):
         if self.message is not None:
             return self.message
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index bf0c4da..955382d 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -21,7 +21,8 @@ Copyright 2010 Sebastian Spaeth <[hidden email]>'
 
 from ctypes import c_char_p, c_long, c_uint, c_int
 from datetime import date
-from notmuch.globals import (nmlib, STATUS, NotmuchError, Enum, _str,
+from notmuch.globals import (
+    nmlib, STATUS, NotmuchError, Enum, _str, Python3StringMixIn,
     NotmuchTagsP, NotmuchMessagesP, NotmuchMessageP, NotmuchFilenamesP)
 from notmuch.tag import Tags
 from notmuch.filename import Filenames
@@ -239,7 +240,7 @@ class Messages(object):
         sys.stdout.write(set_end)
 
 
-class Message(object):
+class Message(Python3StringMixIn):
     """Represents a single Email message
 
     Technically, this wraps the underlying *notmuch_message_t*
@@ -796,9 +797,6 @@ class Message(object):
         """Represent a Message() object by str()"""
         return self.__str__()
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
     def __unicode__(self):
         format = "%s (%s) (%s)"
         return format % (self.get_header('from'),
diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py
index d42ba77..ceb7244 100644
--- a/bindings/python/notmuch/tag.py
+++ b/bindings/python/notmuch/tag.py
@@ -17,10 +17,10 @@ along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
 Copyright 2010 Sebastian Spaeth <[hidden email]>'
 """
 from ctypes import c_char_p
-from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP
+from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP, _str, Python3StringMixIn
 
 
-class Tags(object):
+class Tags(Python3StringMixIn):
     """Represents a list of notmuch tags
 
     This object provides an iterator over a list of notmuch tags (which
@@ -111,9 +111,6 @@ class Tags(object):
             left."""
         return self._valid(self._tags) > 0
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
     def __unicode__(self):
         """string representation of :class:`Tags`: a space separated list of tags
 
diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py
index 39285d6..3912957 100644
--- a/bindings/python/notmuch/thread.py
+++ b/bindings/python/notmuch/thread.py
@@ -20,13 +20,13 @@ Copyright 2010 Sebastian Spaeth <[hidden email]>'
 from ctypes import c_char_p, c_long, c_int
 from notmuch.globals import (nmlib, STATUS,
     NotmuchError, NotmuchThreadP, NotmuchThreadsP, NotmuchMessagesP,
-    NotmuchTagsP,)
+    NotmuchTagsP, Python3StringMixIn)
 from notmuch.message import Messages
 from notmuch.tag import Tags
 from datetime import date
 
 
-class Threads(object):
+class Threads(Python3StringMixIn):
     """Represents a list of notmuch threads
 
     This object provides an iterator over a list of notmuch threads
@@ -393,7 +393,7 @@ class Thread(object):
         return Tags(tags_p, self)
 
     def __str__(self):
-        return unicode(self).encode('utf-8')
+        return self.__unicode__().encode('utf-8')
 
     def __unicode__(self):
         frm = "thread:%s %12s [%d/%d] %s; %s (%s)"
--
1.7.7.3

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 7/7] python: add missing conversions from and to utf-8

In reply to this post by Justus Winter
---
 bindings/python/notmuch/database.py |    6 +++---
 bindings/python/notmuch/filename.py |    2 +-
 bindings/python/notmuch/message.py  |    8 ++++----
 bindings/python/notmuch/thread.py   |    2 +-
 4 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index 3f6e04d..2eae69e 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -430,7 +430,7 @@ class Database(object):
                removed.
         """
         self._assert_db_is_initialized()
-        return self._remove_message(self._db, filename)
+        return self._remove_message(self._db, _str(filename))
 
     def find_message(self, msgid):
         """Returns a :class:`Message` as identified by its message ID
@@ -933,9 +933,9 @@ class Filenames(object):
             self._files_p = None
             raise StopIteration
 
-        file = Filenames._get(self._files_p)
+        file_ = Filenames._get(self._files_p)
         self._move_to_next(self._files_p)
-        return file
+        return file_.decode('utf-8', errors='ignore')
     next = __next__ # python2.x iterator protocol compatibility
 
     def __len__(self):
diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py
index 969931a..0c2e0d5 100644
--- a/bindings/python/notmuch/filename.py
+++ b/bindings/python/notmuch/filename.py
@@ -93,7 +93,7 @@ class Filenames(Python3StringMixIn):
             raise NotmuchError(STATUS.NOT_INITIALIZED)
 
         while self._valid(self._files):
-            yield Filenames._get(self._files)
+            yield Filenames._get(self._files).decode('utf-8', errors='ignore')
             self._move_to_next(self._files)
 
         self._files = None
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index 955382d..245e814 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -338,7 +338,7 @@ class Message(Python3StringMixIn):
         """
         if self._msg is None:
             raise NotmuchError(STATUS.NOT_INITIALIZED)
-        return Message._get_message_id(self._msg)
+        return Message._get_message_id(self._msg).decode('utf-8', errors='ignore')
 
     def get_thread_id(self):
         """Returns the thread ID
@@ -356,7 +356,7 @@ class Message(Python3StringMixIn):
         if self._msg is None:
             raise NotmuchError(STATUS.NOT_INITIALIZED)
 
-        return Message._get_thread_id(self._msg)
+        return Message._get_thread_id(self._msg).decode('utf-8', errors='ignore')
 
     def get_replies(self):
         """Gets all direct replies to this message as :class:`Messages`
@@ -426,7 +426,7 @@ class Message(Python3StringMixIn):
             raise NotmuchError(STATUS.NOT_INITIALIZED)
 
         #Returns NULL if any error occurs.
-        header = Message._get_header(self._msg, header)
+        header = Message._get_header(self._msg, _str(header))
         if header == None:
             raise NotmuchError(STATUS.NULL_POINTER)
         return header.decode('UTF-8', errors='ignore')
@@ -440,7 +440,7 @@ class Message(Python3StringMixIn):
         """
         if self._msg is None:
             raise NotmuchError(STATUS.NOT_INITIALIZED)
-        return Message._get_filename(self._msg)
+        return Message._get_filename(self._msg).decode('utf-8', errors='ignore')
 
     def get_filenames(self):
         """Get all filenames for the email corresponding to 'message'
diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py
index 3912957..2ed7db0 100644
--- a/bindings/python/notmuch/thread.py
+++ b/bindings/python/notmuch/thread.py
@@ -246,7 +246,7 @@ class Thread(object):
         """
         if self._thread is None:
             raise NotmuchError(STATUS.NOT_INITIALIZED)
-        return Thread._get_thread_id(self._thread)
+        return Thread._get_thread_id(self._thread).decode('utf-8', errors='ignore')
 
     _get_total_messages = nmlib.notmuch_thread_get_total_messages
     _get_total_messages.argtypes = [NotmuchThreadP]
--
1.7.7.3

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Tomi Ollila-2 Tomi Ollila-2
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 3/7] py3k: All strings are unicode strings in py3k

In reply to this post by Justus Winter
On Wed, 14 Dec 2011 11:58:21 +0100, Justus Winter <[hidden email]> wrote:

> ---
>  bindings/python/notmuch/globals.py |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
> index 54a49b2..99e6a10 100644
> --- a/bindings/python/notmuch/globals.py
> +++ b/bindings/python/notmuch/globals.py
> @@ -51,7 +51,7 @@ class Status(Enum):
>          """Get a (unicode) string representation of a notmuch_status_t value."""
>          # define strings for custom error messages
>          if status == STATUS.NOT_INITIALIZED:
> -            return u"Operation on uninitialized object impossible."
> +            return "Operation on uninitialized object impossible."
>          return unicode(Status._status2str(status))
>  
>  STATUS = Status(['SUCCESS',
> @@ -142,7 +142,7 @@ class NotmuchError(Exception):
>          elif self.status is not None:
>              return STATUS.status2str(self.status)
>          else:
> -            return u'Unknown error'
> +            return 'Unknown error'

Is this u -prefix unnecessary in python 2 too ? Grepping
'u"' and "u'" in **/*.py in puthon bindings source resulted
some more u-prefixed strings in docs/source/conf.py. Should
these be changed in some future patch ?

>  # List of Subclassed exceptions that correspond to STATUS values and are
> --
> 1.7.7.3

Tomi
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Tomi Ollila-2 Tomi Ollila-2
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 6/7] py3k: Add and use a mixin class that implements __str__

In reply to this post by Justus Winter
On Wed, 14 Dec 2011 11:58:24 +0100, Justus Winter <[hidden email]> wrote:
> ---
[ ... snip ... ]

>  
> -class Filenames(object):
> +class Filenames(Python3StringMixIn):
>      """Represents a list of filenames as returned by notmuch
>  
>      This object contains the Filenames iterator. The main function is
> @@ -98,9 +98,6 @@ class Filenames(object):
>  
>          self._files = None
>  
> -    def __str__(self):
> -        return unicode(self).encode('utf-8')
> -
>      def __unicode__(self):
>          """Represent Filenames() as newline-separated list of full paths
>  
> diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
> index c52790c..2111b86 100644
> --- a/bindings/python/notmuch/globals.py
> +++ b/bindings/python/notmuch/globals.py
> @@ -28,6 +28,16 @@ except:
>      raise ImportError("Could not find shared 'notmuch' library.")
>  
>  
> +if sys.version_info[0] == 2:
> +    class Python3StringMixIn(object):
> +        def __str__(self):
> +            return unicode(self).encode('utf-8')
> +else:
> +    class Python3StringMixIn(object):
> +        def __str__(self):
> +            return self.__unicode__()
> +
> +

[ ... snip ... ]

> -class Threads(object):
> +class Threads(Python3StringMixIn):
>      """Represents a list of notmuch threads
>  
>      This object provides an iterator over a list of notmuch threads
> @@ -393,7 +393,7 @@ class Thread(object):
>          return Tags(tags_p, self)
>  
>      def __str__(self):
> -        return unicode(self).encode('utf-8')
> +        return self.__unicode__().encode('utf-8')
>  
>      def __unicode__(self):
>          frm = "thread:%s %12s [%d/%d] %s; %s (%s)"

Is this class special case ? in all other classes
the __str__() function has been removed (using inherited
function) ?

> --
> 1.7.7.3

Otherwise LGTM -- pretty simple and effective (all 7 patches).

Tomi

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 3/7] py3k: All strings are unicode strings in py3k

In reply to this post by Tomi Ollila-2
Hi Tomi :)

Quoting Tomi Ollila (2011-12-14 13:17:41)

>On Wed, 14 Dec 2011 11:58:21 +0100, Justus Winter <[hidden email]> wrote:
>> ---
>>  bindings/python/notmuch/globals.py |    4 ++--
>>  1 files changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
>> index 54a49b2..99e6a10 100644
>> --- a/bindings/python/notmuch/globals.py
>> +++ b/bindings/python/notmuch/globals.py
>> @@ -51,7 +51,7 @@ class Status(Enum):
>>          """Get a (unicode) string representation of a notmuch_status_t value."""
>>          # define strings for custom error messages
>>          if status == STATUS.NOT_INITIALIZED:
>> -            return u"Operation on uninitialized object impossible."
>> +            return "Operation on uninitialized object impossible."
>>          return unicode(Status._status2str(status))
>>  
>>  STATUS = Status(['SUCCESS',
>> @@ -142,7 +142,7 @@ class NotmuchError(Exception):
>>          elif self.status is not None:
>>              return STATUS.status2str(self.status)
>>          else:
>> -            return u'Unknown error'
>> +            return 'Unknown error'
>
>Is this u -prefix unnecessary in python 2 too ? Grepping
>'u"' and "u'" in **/*.py in puthon bindings source resulted
>some more u-prefixed strings in docs/source/conf.py. Should
>these be changed in some future patch ?
Well, since the string literal contains no non-ascii characters it is
perfectly safe to just use a (python2.x) string literal and it will be
automatically coerced to unicode if it is used in a unicode context.

OTOH it is possible to use

from __future__ import unicode_literals

to turn all string literals to unicode literals in python 2.x.

Justus

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch

.signature (26 bytes) Download Attachment
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 6/7] py3k: Add and use a mixin class that implements __str__

In reply to this post by Tomi Ollila-2
Quoting Tomi Ollila (2011-12-14 13:26:38)

>On Wed, 14 Dec 2011 11:58:24 +0100, Justus Winter <[hidden email]> wrote:
>> ---
>[ ... snip ... ]
>
>>  
>> -class Filenames(object):
>> +class Filenames(Python3StringMixIn):
>>      """Represents a list of filenames as returned by notmuch
>>  
>>      This object contains the Filenames iterator. The main function is
>> @@ -98,9 +98,6 @@ class Filenames(object):
>>  
>>          self._files = None
>>  
>> -    def __str__(self):
>> -        return unicode(self).encode('utf-8')
>> -
>>      def __unicode__(self):
>>          """Represent Filenames() as newline-separated list of full paths
>>  
>> diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
>> index c52790c..2111b86 100644
>> --- a/bindings/python/notmuch/globals.py
>> +++ b/bindings/python/notmuch/globals.py
>> @@ -28,6 +28,16 @@ except:
>>      raise ImportError("Could not find shared 'notmuch' library.")
>>  
>>  
>> +if sys.version_info[0] == 2:
>> +    class Python3StringMixIn(object):
>> +        def __str__(self):
>> +            return unicode(self).encode('utf-8')
>> +else:
>> +    class Python3StringMixIn(object):
>> +        def __str__(self):
>> +            return self.__unicode__()
>> +
>> +
>
>[ ... snip ... ]
>
>> -class Threads(object):
>> +class Threads(Python3StringMixIn):
>>      """Represents a list of notmuch threads
>>  
>>      This object provides an iterator over a list of notmuch threads
>> @@ -393,7 +393,7 @@ class Thread(object):
>>          return Tags(tags_p, self)
>>  
>>      def __str__(self):
>> -        return unicode(self).encode('utf-8')
>> +        return self.__unicode__().encode('utf-8')
>>  
>>      def __unicode__(self):
>>          frm = "thread:%s %12s [%d/%d] %s; %s (%s)"
>
>Is this class special case ? in all other classes
>the __str__() function has been removed (using inherited
>function) ?
Damn, I missed that one... that was my first approach but that
obviously didn't worked out... I'll send an updated patch.

>Otherwise LGTM -- pretty simple and effective (all 7 patches).

Thanks :)

Note that I do not know how complete the port is. But the stuff used
by my tagging application (afew) works.

Justus

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch

.signature (26 bytes) Download Attachment
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 6/7] py3k: Add and use a mixin class that implements __str__

---
 bindings/python/notmuch/filename.py |    7 ++-----
 bindings/python/notmuch/globals.py  |   15 +++++++++++----
 bindings/python/notmuch/message.py  |    8 +++-----
 bindings/python/notmuch/tag.py      |    7 ++-----
 bindings/python/notmuch/thread.py   |    7 ++-----
 5 files changed, 20 insertions(+), 24 deletions(-)

diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py
index a7cd7e6..969931a 100644
--- a/bindings/python/notmuch/filename.py
+++ b/bindings/python/notmuch/filename.py
@@ -18,10 +18,10 @@ Copyright 2010 Sebastian Spaeth <[hidden email]>'
 """
 from ctypes import c_char_p
 from notmuch.globals import (nmlib, STATUS, NotmuchError,
-    NotmuchFilenamesP, NotmuchMessageP)
+    NotmuchFilenamesP, NotmuchMessageP, _str, Python3StringMixIn)
 
 
-class Filenames(object):
+class Filenames(Python3StringMixIn):
     """Represents a list of filenames as returned by notmuch
 
     This object contains the Filenames iterator. The main function is
@@ -98,9 +98,6 @@ class Filenames(object):
 
         self._files = None
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
     def __unicode__(self):
         """Represent Filenames() as newline-separated list of full paths
 
diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index c52790c..2111b86 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -28,6 +28,16 @@ except:
     raise ImportError("Could not find shared 'notmuch' library.")
 
 
+if sys.version_info[0] == 2:
+    class Python3StringMixIn(object):
+        def __str__(self):
+            return unicode(self).encode('utf-8')
+else:
+    class Python3StringMixIn(object):
+        def __str__(self):
+            return self.__unicode__()
+
+
 class Enum(object):
     """Provides ENUMS as "code=Enum(['a','b','c'])" where code.a=0 etc..."""
     def __init__(self, names):
@@ -90,7 +100,7 @@ argument to receive a human readable string"""
 STATUS.__name__ = 'STATUS'
 
 
-class NotmuchError(Exception):
+class NotmuchError(Exception, Python3StringMixIn):
     """Is initiated with a (notmuch.STATUS[, message=None]). It will not
     return an instance of the class NotmuchError, but a derived instance
     of a more specific Error Message, e.g. OutOfMemoryError. Each status
@@ -134,9 +144,6 @@ class NotmuchError(Exception):
         self.status = status
         self.message = message
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
     def __unicode__(self):
         if self.message is not None:
             return self.message
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index bf0c4da..955382d 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -21,7 +21,8 @@ Copyright 2010 Sebastian Spaeth <[hidden email]>'
 
 from ctypes import c_char_p, c_long, c_uint, c_int
 from datetime import date
-from notmuch.globals import (nmlib, STATUS, NotmuchError, Enum, _str,
+from notmuch.globals import (
+    nmlib, STATUS, NotmuchError, Enum, _str, Python3StringMixIn,
     NotmuchTagsP, NotmuchMessagesP, NotmuchMessageP, NotmuchFilenamesP)
 from notmuch.tag import Tags
 from notmuch.filename import Filenames
@@ -239,7 +240,7 @@ class Messages(object):
         sys.stdout.write(set_end)
 
 
-class Message(object):
+class Message(Python3StringMixIn):
     """Represents a single Email message
 
     Technically, this wraps the underlying *notmuch_message_t*
@@ -796,9 +797,6 @@ class Message(object):
         """Represent a Message() object by str()"""
         return self.__str__()
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
     def __unicode__(self):
         format = "%s (%s) (%s)"
         return format % (self.get_header('from'),
diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py
index d42ba77..ceb7244 100644
--- a/bindings/python/notmuch/tag.py
+++ b/bindings/python/notmuch/tag.py
@@ -17,10 +17,10 @@ along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
 Copyright 2010 Sebastian Spaeth <[hidden email]>'
 """
 from ctypes import c_char_p
-from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP
+from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP, _str, Python3StringMixIn
 
 
-class Tags(object):
+class Tags(Python3StringMixIn):
     """Represents a list of notmuch tags
 
     This object provides an iterator over a list of notmuch tags (which
@@ -111,9 +111,6 @@ class Tags(object):
             left."""
         return self._valid(self._tags) > 0
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
     def __unicode__(self):
         """string representation of :class:`Tags`: a space separated list of tags
 
diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py
index 39285d6..7393097 100644
--- a/bindings/python/notmuch/thread.py
+++ b/bindings/python/notmuch/thread.py
@@ -20,13 +20,13 @@ Copyright 2010 Sebastian Spaeth <[hidden email]>'
 from ctypes import c_char_p, c_long, c_int
 from notmuch.globals import (nmlib, STATUS,
     NotmuchError, NotmuchThreadP, NotmuchThreadsP, NotmuchMessagesP,
-    NotmuchTagsP,)
+    NotmuchTagsP, Python3StringMixIn)
 from notmuch.message import Messages
 from notmuch.tag import Tags
 from datetime import date
 
 
-class Threads(object):
+class Threads(Python3StringMixIn):
     """Represents a list of notmuch threads
 
     This object provides an iterator over a list of notmuch threads
@@ -392,9 +392,6 @@ class Thread(object):
             raise NotmuchError(STATUS.NULL_POINTER)
         return Tags(tags_p, self)
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
     def __unicode__(self):
         frm = "thread:%s %12s [%d/%d] %s; %s (%s)"
 
--
1.7.7.3

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
spaetz spaetz
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 5/7] py3k: the basestring and unicode types are removed in python 3

In reply to this post by Justus Winter
Happy new year. Pushed patches 1-4 of this series so far. Looking fine,
but ugh, the below seems like a rather ugly hack in a function that is
probably called quite often.

Isn't there a more pretty variant avoiding these sys.version_info checks
all over the place?

> @@ -200,9 +201,9 @@ def _str(value):
>  
>      C++ code expects strings to be well formatted and
>      unicode strings to have no null bytes."""
> -    if not isinstance(value, basestring):
> +    if not isinstance(value, basestring if sys.version_info[0] == 2 else str):
>          raise TypeError("Expected str or unicode, got %s" % str(type(value)))
> -    if isinstance(value, unicode):
> +    if sys.version_info[0] == 3 or isinstance(value, unicode):
>          return value.encode('UTF-8')
>      return value

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch

attachment0 (203 bytes) Download Attachment
Tomi Ollila-2 Tomi Ollila-2
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 5/7] py3k: the basestring and unicode types are removed in python 3

On Mon, 02 Jan 2012 16:15:58 +0100, Sebastian Spaeth <[hidden email]> wrote:

> Happy new year. Pushed patches 1-4 of this series so far. Looking fine,
> but ugh, the below seems like a rather ugly hack in a function that is
> probably called quite often.
>
> Isn't there a more pretty variant avoiding these sys.version_info checks
> all over the place?
>
> > @@ -200,9 +201,9 @@ def _str(value):
> >  
> >      C++ code expects strings to be well formatted and
> >      unicode strings to have no null bytes."""
> > -    if not isinstance(value, basestring):
> > +    if not isinstance(value, basestring if sys.version_info[0] == 2 else str):
> >          raise TypeError("Expected str or unicode, got %s" % str(type(value)))
> > -    if isinstance(value, unicode):
> > +    if sys.version_info[0] == 3 or isinstance(value, unicode):
> >          return value.encode('UTF-8')
> >      return value

Does the Python3StringMixIn stuff in later patches already handle this
patch -- and making this obsolete ?

Tomi
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 5/7] py3k: the basestring and unicode types are removed in python 3

Hi Tomi, Hi Sebastian :)

Quoting Tomi Ollila (2012-01-04 19:07:11)
>On Mon, 02 Jan 2012 16:15:58 +0100, Sebastian Spaeth <[hidden email]> wrote:
>> Happy new year. Pushed patches 1-4 of this series so far. Looking fine,

nice, thanks.

>> but ugh, the below seems like a rather ugly hack in a function that is
>> probably called quite often.
>>
>> Isn't there a more pretty variant avoiding these sys.version_info checks
>> all over the place?

Well, I rebased and updated this patch. There are now two different
implementations of _str like there are two Python3StringMixIn
classes. I'll send this patch as reply to this message.

>Does the Python3StringMixIn stuff in later patches already handle this
>patch -- and making this obsolete ?

No, that only handles the __str__ and __unicode__ stuff.

Cheers,
Justus
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH] py3k: the basestring and unicode types are removed in python 3

---
 bindings/python/notmuch/globals.py |   34 ++++++++++++++++++++++------------
 1 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 32ed9ae..4138460 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -31,12 +31,34 @@ if sys.version_info[0] == 2:
     class Python3StringMixIn(object):
         def __str__(self):
             return unicode(self).encode('utf-8')
+
+
+    def _str(value):
+        """Ensure a nicely utf-8 encoded string to pass to libnotmuch
+
+        C++ code expects strings to be well formatted and
+        unicode strings to have no null bytes."""
+        if not isinstance(value, basestring):
+            raise TypeError("Expected str or unicode, got %s" % type(value))
+        if isinstance(value, unicode):
+            return value.encode('UTF-8')
+        return value
 else:
     class Python3StringMixIn(object):
         def __str__(self):
             return self.__unicode__()
 
 
+    def _str(value):
+        """Ensure a nicely utf-8 encoded string to pass to libnotmuch
+
+        C++ code expects strings to be well formatted and
+        unicode strings to have no null bytes."""
+        if not isinstance(value, str):
+            raise TypeError("Expected str, got %s" % type(value))
+        return value.encode('UTF-8')
+
+
 class Enum(object):
     """Provides ENUMS as "code=Enum(['a','b','c'])" where code.a=0 etc..."""
     def __init__(self, names):
@@ -202,18 +224,6 @@ class NotInitializedError(NotmuchError):
     status = STATUS.NOT_INITIALIZED
 
 
-def _str(value):
-    """Ensure a nicely utf-8 encoded string to pass to libnotmuch
-
-    C++ code expects strings to be well formatted and
-    unicode strings to have no null bytes."""
-    if not isinstance(value, basestring):
-        raise TypeError("Expected str or unicode, got %s" % str(type(value)))
-    if isinstance(value, unicode):
-        return value.encode('UTF-8')
-    return value
-
-
 class NotmuchDatabaseS(Structure):
     pass
 NotmuchDatabaseP = POINTER(NotmuchDatabaseS)
--
1.7.7.3

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch