Hello community,

here is the log from the commit of package python-imbox for openSUSE:Factory 
checked in at 2018-09-03 10:36:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-imbox (Old)
 and      /work/SRC/openSUSE:Factory/.python-imbox.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-imbox"

Mon Sep  3 10:36:32 2018 rev:4 rq:632744 version:0.9.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-imbox/python-imbox.changes        
2017-12-14 11:01:34.563760118 +0100
+++ /work/SRC/openSUSE:Factory/.python-imbox.new/python-imbox.changes   
2018-09-03 10:36:34.884898680 +0200
@@ -1,0 +2,9 @@
+Sun Aug 26 12:04:54 UTC 2018 - [email protected]
+
+- update to 0.9.6:
+ * Vendors package, adding provider specific functionality 
([#139](https://github.com/martinrusev/imbox/pull/139)) -  Contributed by 
@zevaverbach
+ * Type hints for every method and function 
([#136](https://github.com/martinrusev/imbox/pull/136)) -  Contributed by 
@zevaverbach
+ * Move all code out of __init__.py and into a separate module 
([#130](https://github.com/martinrusev/imbox/pull/130)) - Contributed by 
@zevaverbach
+ * Enhance `messages' generator: 
([#129](https://github.com/martinrusev/imbox/pull/129)) - Contributed by 
@zevaverbach
+
+-------------------------------------------------------------------

Old:
----
  imbox-0.9.5.tar.gz

New:
----
  imbox-0.9.6.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-imbox.spec ++++++
--- /var/tmp/diff_new_pack.VM6ODD/_old  2018-09-03 10:36:35.292899736 +0200
+++ /var/tmp/diff_new_pack.VM6ODD/_new  2018-09-03 10:36:35.296899747 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-imbox
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-imbox
-Version:        0.9.5
+Version:        0.9.6
 Release:        0
 Summary:        Python IMAP for Human beings
 License:        MIT
@@ -46,7 +46,8 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %files %{python_files}
-%doc README.rst LICENSE
+%doc README.rst
+%license LICENSE
 %{python_sitelib}/*
 
 %changelog

++++++ imbox-0.9.5.tar.gz -> imbox-0.9.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/CHANGELOG.md new/imbox-0.9.6/CHANGELOG.md
--- old/imbox-0.9.5/CHANGELOG.md        2017-12-05 18:55:07.000000000 +0100
+++ new/imbox-0.9.6/CHANGELOG.md        2018-08-14 17:23:46.000000000 +0200
@@ -1,22 +1,32 @@
+## 0.9.6 (16 August 2018)
+
+IMPROVEMENTS:
+
+ * Vendors package, adding provider specific functionality 
([#139](https://github.com/martinrusev/imbox/pull/139)) -  Contributed by 
@zevaverbach
+ * Type hints for every method and function 
([#136](https://github.com/martinrusev/imbox/pull/136)) -  Contributed by 
@zevaverbach
+ * Move all code out of __init__.py and into a separate module 
([#130](https://github.com/martinrusev/imbox/pull/130)) - Contributed by 
@zevaverbach
+ * Enhance `messages' generator: 
([#129](https://github.com/martinrusev/imbox/pull/129)) - Contributed by 
@zevaverbach
+
+
 ## 0.9.5 (5 December 2017)
 
 IMPROVEMENTS:
 
- * `date__on` support: ([#109](https://github.com/martinrusev/imbox/pull/109))
- * Starttls support: ([#108](https://github.com/martinrusev/imbox/pull/108))
- * Mark emails as flagged/starred: 
([#107](https://github.com/martinrusev/imbox/pull/107))
- * Messages filter can use date objects instead of stringified dates: 
([#104](https://github.com/martinrusev/imbox/pull/104))
- * Fix attachment parsing when a semicolon character ends the 
Content-Disposition line: 
([#100](https://github.com/martinrusev/imbox/pull/100))
- * Parsing - UnicecodeDecodeError() fixes: 
([#96](https://github.com/martinrusev/imbox/pull/96))
- * Imbox() `with` support: 
([#92](https://github.com/martinrusev/imbox/pull/92))
+ * `date__on` support: ([#109](https://github.com/martinrusev/imbox/pull/109)) 
- Contributed by @balsagoth
+ * Starttls support: ([#108](https://github.com/martinrusev/imbox/pull/108)) - 
Contributed by @balsagoth
+ * Mark emails as flagged/starred: 
([#107](https://github.com/martinrusev/imbox/pull/107)) - Contributed by 
@memanikantan
+ * Messages filter can use date objects instead of stringified dates: 
([#104](https://github.com/martinrusev/imbox/pull/104)) - Contributed by 
@sblondon
+ * Fix attachment parsing when a semicolon character ends the 
Content-Disposition line: 
([#100](https://github.com/martinrusev/imbox/pull/100)) - Contributed by 
@sblondon
+ * Parsing - UnicecodeDecodeError() fixes: 
([#96](https://github.com/martinrusev/imbox/pull/96)) - Contributed by @am0z
+ * Imbox() `with` support: 
([#92](https://github.com/martinrusev/imbox/pull/92)) - Contributed by @sblondon
 
 
 ## 0.9 (18 September 2017)
 
 IMPROVEMENTS:
 
- * Permissively Decode Emails: 
([#78](https://github.com/martinrusev/imbox/pull/78))
- * "With" statement for automatic cleanup/logout 
([#92](https://github.com/martinrusev/imbox/pull/92))
+ * Permissively Decode Emails: 
([#78](https://github.com/martinrusev/imbox/pull/78)) - Contributed by 
@AdamNiederer
+ * "With" statement for automatic cleanup/logout 
([#92](https://github.com/martinrusev/imbox/pull/92)) - Contributed by @sblondon
  
 
 
@@ -24,7 +34,7 @@
 
 IMPROVEMENTS:
 
- * Add support for Python 3.3+  Parsing policies: 
([#75](https://github.com/martinrusev/imbox/pull/75))
+ * Add support for Python 3.3+  Parsing policies: 
([#75](https://github.com/martinrusev/imbox/pull/75)) - Contributed by @bhtucker
  
 BACKWARDS INCOMPATIBILITIES / NOTES:
 
@@ -35,4 +45,4 @@
 
 IMPROVEMENTS:
 
- * ssl_context: Check SSLContext for IMAP4_SSL connections  
([#69](https://github.com/martinrusev/imbox/pull/69))
+ * ssl_context: Check SSLContext for IMAP4_SSL connections  
([#69](https://github.com/martinrusev/imbox/pull/69)) - Contributed by @dmth
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/PKG-INFO new/imbox-0.9.6/PKG-INFO
--- old/imbox-0.9.5/PKG-INFO    2017-12-05 19:09:13.000000000 +0100
+++ new/imbox-0.9.6/PKG-INFO    2018-08-14 17:26:01.000000000 +0200
@@ -1,12 +1,11 @@
 Metadata-Version: 1.1
 Name: imbox
-Version: 0.9.5
+Version: 0.9.6
 Summary: Python IMAP for Human beings
 Home-page: https://github.com/martinrusev/imbox
 Author: Martin Rusev
 Author-email: [email protected]
 License: MIT
-Description-Content-Type: UNKNOWN
 Description: Imbox - Python IMAP for Humans
         ==============================
         
@@ -45,36 +44,50 @@
                     ssl=True,
                     ssl_context=None,
                     starttls=False) as imbox:
+        
                 # Get all folders
                 status, folders_with_additional_info = imbox.folders()
         
-                # Gets all messages
-                all_messages = imbox.messages()
+                # Gets all messages from the inbox
+                all_inbox_messages = imbox.messages()
         
                 # Unread messages
-                unread_messages = imbox.messages(unread=True)
+                unread_inbox_messages = imbox.messages(unread=True)
+        
+                # Flagged messages
+                inbox_flagged_messages = imbox.messages(flagged=True)
+        
+                # Un-flagged messages
+                inbox_unflagged_messages = imbox.messages(unflagged=True)
+        
+                # Flagged messages
+                flagged_messages = imbox.messages(flagged=True)
+        
+                # Un-flagged messages
+                unflagged_messages = imbox.messages(unflagged=True)
         
                 # Messages sent FROM
-                messages_from = imbox.messages(sent_from='[email protected]')
+                inbox_messages_from = 
imbox.messages(sent_from='[email protected]')
         
                 # Messages sent TO
-                messages_from = imbox.messages(sent_to='[email protected]')
+                inbox_messages_to = 
imbox.messages(sent_to='[email protected]')
         
                 # Messages received before specific date
-                messages_from = imbox.messages(date__lt=datetime.date(2013, 7, 
31))
+                inbox_messages_received_before = 
imbox.messages(date__lt=datetime.date(2018, 7, 31))
         
                 # Messages received after specific date
-                messages_from = imbox.messages(date__gt=datetime.date(2013, 7, 
30))
+                inbox_messages_received_after = 
imbox.messages(date__gt=datetime.date(2018, 7, 30))
         
                 # Messages received on a specific date
-                messages_from = imbox.messages(date__on=datetime.date(2013, 7, 
30))
-        
-                # Messages from a specific folder
-                messages_folder = imbox.messages(folder='Social')
+                inbox_messages_received_on_date = 
imbox.messages(date__on=datetime.date(2018, 7, 30))
         
+                # Messages whose subjects contain a string
+                inbox_messages_subject_christmas = 
imbox.messages(subject='Christmas')
         
+                # Messages from a specific folder
+                messages_in_folder_social = imbox.messages(folder='Social')
         
-                for uid, message in all_messages:
+                for uid, message in all_inbox_messages:
                 # Every message is an object with the following keys
         
                     message.sent_from
@@ -134,7 +147,7 @@
         
                 # mark the message as read
                 imbox.mark_seen(uid)
-                
+        
         
         
         Changelog
@@ -167,3 +180,4 @@
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/README.rst new/imbox-0.9.6/README.rst
--- old/imbox-0.9.5/README.rst  2017-12-05 18:44:32.000000000 +0100
+++ new/imbox-0.9.6/README.rst  2018-08-14 17:22:47.000000000 +0200
@@ -36,36 +36,50 @@
             ssl=True,
             ssl_context=None,
             starttls=False) as imbox:
+
         # Get all folders
         status, folders_with_additional_info = imbox.folders()
 
-        # Gets all messages
-        all_messages = imbox.messages()
+        # Gets all messages from the inbox
+        all_inbox_messages = imbox.messages()
 
         # Unread messages
-        unread_messages = imbox.messages(unread=True)
+        unread_inbox_messages = imbox.messages(unread=True)
+
+        # Flagged messages
+        inbox_flagged_messages = imbox.messages(flagged=True)
+
+        # Un-flagged messages
+        inbox_unflagged_messages = imbox.messages(unflagged=True)
+
+        # Flagged messages
+        flagged_messages = imbox.messages(flagged=True)
+
+        # Un-flagged messages
+        unflagged_messages = imbox.messages(unflagged=True)
 
         # Messages sent FROM
-        messages_from = imbox.messages(sent_from='[email protected]')
+        inbox_messages_from = imbox.messages(sent_from='[email protected]')
 
         # Messages sent TO
-        messages_from = imbox.messages(sent_to='[email protected]')
+        inbox_messages_to = imbox.messages(sent_to='[email protected]')
 
         # Messages received before specific date
-        messages_from = imbox.messages(date__lt=datetime.date(2013, 7, 31))
+        inbox_messages_received_before = 
imbox.messages(date__lt=datetime.date(2018, 7, 31))
 
         # Messages received after specific date
-        messages_from = imbox.messages(date__gt=datetime.date(2013, 7, 30))
+        inbox_messages_received_after = 
imbox.messages(date__gt=datetime.date(2018, 7, 30))
 
         # Messages received on a specific date
-        messages_from = imbox.messages(date__on=datetime.date(2013, 7, 30))
-
-        # Messages from a specific folder
-        messages_folder = imbox.messages(folder='Social')
+        inbox_messages_received_on_date = 
imbox.messages(date__on=datetime.date(2018, 7, 30))
 
+        # Messages whose subjects contain a string
+        inbox_messages_subject_christmas = imbox.messages(subject='Christmas')
 
+        # Messages from a specific folder
+        messages_in_folder_social = imbox.messages(folder='Social')
 
-        for uid, message in all_messages:
+        for uid, message in all_inbox_messages:
         # Every message is an object with the following keys
 
             message.sent_from
@@ -125,7 +139,7 @@
 
         # mark the message as read
         imbox.mark_seen(uid)
-        
+
 
 
 Changelog
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox/__init__.py 
new/imbox-0.9.6/imbox/__init__.py
--- old/imbox-0.9.5/imbox/__init__.py   2017-12-05 18:44:32.000000000 +0100
+++ new/imbox-0.9.6/imbox/__init__.py   2018-08-14 17:24:05.000000000 +0200
@@ -1,93 +1,9 @@
-from imbox.imap import ImapTransport
-from imbox.parser import parse_email
-from imbox.query import build_search_query
+from imbox.imbox import Imbox
 
-import logging
-logger = logging.getLogger(__name__)
+__version_info__ = (0, 9, 6)
+__version__ = '.'.join([str(x) for x in __version_info__])
 
 
-class Imbox:
+__all__ = ['Imbox']
 
-    def __init__(self, hostname, username=None, password=None, ssl=True,
-                 port=None, ssl_context=None, policy=None, starttls=False):
 
-        self.server = ImapTransport(hostname, ssl=ssl, port=port,
-                                    ssl_context=ssl_context, starttls=starttls)
-        self.hostname = hostname
-        self.username = username
-        self.password = password
-        self.parser_policy = policy
-        self.connection = self.server.connect(username, password)
-        logger.info("Connected to IMAP Server with user {username} on 
{hostname}{ssl}".format(
-            hostname=hostname, username=username, ssl=(" over SSL" if ssl or 
starttls else "")))
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, type, value, traceback):
-        self.logout()
-
-    def logout(self):
-        self.connection.close()
-        self.connection.logout()
-        logger.info("Disconnected from IMAP Server 
{username}@{hostname}".format(
-            hostname=self.hostname, username=self.username))
-
-    def query_uids(self, **kwargs):
-        query = build_search_query(**kwargs)
-        message, data = self.connection.uid('search', None, query)
-        if data[0] is None:
-            return []
-        return data[0].split()
-
-    def fetch_by_uid(self, uid):
-        message, data = self.connection.uid('fetch', uid, '(BODY.PEEK[])')
-        logger.debug("Fetched message for UID {}".format(int(uid)))
-        raw_email = data[0][1]
-
-        email_object = parse_email(raw_email, policy=self.parser_policy)
-
-        return email_object
-
-    def fetch_list(self, **kwargs):
-        uid_list = self.query_uids(**kwargs)
-        logger.debug("Fetch all messages for UID in {}".format(uid_list))
-
-        for uid in uid_list:
-            yield (uid, self.fetch_by_uid(uid))
-
-    def mark_seen(self, uid):
-        logger.info("Mark UID {} with \\Seen FLAG".format(int(uid)))
-        self.connection.uid('STORE', uid, '+FLAGS', '(\\Seen)')
-
-    def mark_flag(self, uid):
-        logger.info("Mark UID {} with \\Flagged FLAG".format(int(uid)))
-        self.connection.uid('STORE', uid, '+FLAGS', '(\\Flagged)')
-
-    def delete(self, uid):
-        logger.info("Mark UID {} with \\Deleted FLAG and 
expunge.".format(int(uid)))
-        mov, data = self.connection.uid('STORE', uid, '+FLAGS', '(\\Deleted)')
-        self.connection.expunge()
-
-    def copy(self, uid, destination_folder):
-        logger.info("Copy UID {} to {} folder".format(int(uid), 
str(destination_folder)))
-        return self.connection.uid('COPY', uid, destination_folder)
-
-    def move(self, uid, destination_folder):
-        logger.info("Move UID {} to {} folder".format(int(uid), 
str(destination_folder)))
-        if self.copy(uid, destination_folder):
-            self.delete(uid)
-
-    def messages(self, *args, **kwargs):
-        folder = kwargs.get('folder', False)
-        msg = ""
-
-        if folder:
-            self.connection.select(folder)
-            msg = " from folder '{}'".format(folder)
-
-        logger.info("Fetch list of messages{}".format(msg))
-        return self.fetch_list(**kwargs)
-
-    def folders(self):
-        return self.connection.list()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox/imap.py 
new/imbox-0.9.6/imbox/imap.py
--- old/imbox-0.9.5/imbox/imap.py       2017-12-05 18:44:32.000000000 +0100
+++ new/imbox-0.9.6/imbox/imap.py       2018-08-14 17:22:47.000000000 +0200
@@ -10,22 +10,16 @@
 
     def __init__(self, hostname, port=None, ssl=True, ssl_context=None, 
starttls=False):
         self.hostname = hostname
-        self.port = port
-        kwargs = {}
 
         if ssl:
-            self.transport = IMAP4_SSL
-            if not self.port:
-                self.port = 993
+            self.port = port or 993
             if ssl_context is None:
                 ssl_context = pythonssllib.create_default_context()
-            kwargs["ssl_context"] = ssl_context
+            self.server = IMAP4_SSL(self.hostname, self.port, 
ssl_context=ssl_context)
         else:
-            self.transport = IMAP4
-            if not self.port:
-                self.port = 143
+            self.port = port or 143
+            self.server = IMAP4(self.hostname, self.port)
 
-        self.server = self.transport(self.hostname, self.port, **kwargs)
         if starttls:
             self.server.starttls()
         logger.debug("Created IMAP4 transport for {host}:{port}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox/imbox.py 
new/imbox-0.9.6/imbox/imbox.py
--- old/imbox-0.9.5/imbox/imbox.py      1970-01-01 01:00:00.000000000 +0100
+++ new/imbox-0.9.6/imbox/imbox.py      2018-08-14 17:22:47.000000000 +0200
@@ -0,0 +1,98 @@
+import imaplib
+
+from imbox.imap import ImapTransport
+from imbox.messages import Messages
+
+import logging
+
+from imbox.vendors import GmailMessages, hostname_vendorname_dict, 
name_authentication_string_dict
+
+logger = logging.getLogger(__name__)
+
+
+class Imbox:
+
+    authentication_error_message = None
+
+    def __init__(self, hostname, username=None, password=None, ssl=True,
+                 port=None, ssl_context=None, policy=None, starttls=False,
+                 vendor=None):
+
+        self.server = ImapTransport(hostname, ssl=ssl, port=port,
+                                    ssl_context=ssl_context, starttls=starttls)
+
+        self.hostname = hostname
+        self.username = username
+        self.password = password
+        self.parser_policy = policy
+        self.vendor = vendor or hostname_vendorname_dict.get(self.hostname)
+
+        if self.vendor is not None:
+            self.authentication_error_message = 
name_authentication_string_dict.get(self.vendor)
+
+        try:
+            self.connection = self.server.connect(username, password)
+        except imaplib.IMAP4.error as e:
+            if self.authentication_error_message is None:
+                raise
+            raise imaplib.IMAP4.error(self.authentication_error_message + '\n' 
+ str(e))
+
+        logger.info("Connected to IMAP Server with user {username} on 
{hostname}{ssl}".format(
+            hostname=hostname, username=username, ssl=(" over SSL" if ssl or 
starttls else "")))
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, traceback):
+        self.logout()
+
+    def logout(self):
+        self.connection.close()
+        self.connection.logout()
+        logger.info("Disconnected from IMAP Server 
{username}@{hostname}".format(
+            hostname=self.hostname, username=self.username))
+
+    def mark_seen(self, uid):
+        logger.info("Mark UID {} with \\Seen FLAG".format(int(uid)))
+        self.connection.uid('STORE', uid, '+FLAGS', '(\\Seen)')
+
+    def mark_flag(self, uid):
+        logger.info("Mark UID {} with \\Flagged FLAG".format(int(uid)))
+        self.connection.uid('STORE', uid, '+FLAGS', '(\\Flagged)')
+
+    def delete(self, uid):
+        logger.info("Mark UID {} with \\Deleted FLAG and 
expunge.".format(int(uid)))
+        self.connection.uid('STORE', uid, '+FLAGS', '(\\Deleted)')
+        self.connection.expunge()
+
+    def copy(self, uid, destination_folder):
+        logger.info("Copy UID {} to {} folder".format(int(uid), 
str(destination_folder)))
+        return self.connection.uid('COPY', uid, destination_folder)
+
+    def move(self, uid, destination_folder):
+        logger.info("Move UID {} to {} folder".format(int(uid), 
str(destination_folder)))
+        if self.copy(uid, destination_folder):
+            self.delete(uid)
+
+    def messages(self, **kwargs):
+        folder = kwargs.get('folder', False)
+
+        messages_class = Messages
+
+        if self.vendor == 'gmail':
+            messages_class = GmailMessages
+
+        if folder:
+            
self.connection.select(messages_class.folder_lookup.get((folder.lower())) or 
folder)
+            msg = " from folder '{}'".format(folder)
+        else:
+            msg = " from inbox"
+
+        logger.info("Fetch list of messages{}".format(msg))
+
+        return messages_class(connection=self.connection,
+                              parser_policy=self.parser_policy,
+                              **kwargs)
+
+    def folders(self):
+        return self.connection.list()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox/messages.py 
new/imbox-0.9.6/imbox/messages.py
--- old/imbox-0.9.5/imbox/messages.py   1970-01-01 01:00:00.000000000 +0100
+++ new/imbox-0.9.6/imbox/messages.py   2018-08-14 17:22:47.000000000 +0200
@@ -0,0 +1,64 @@
+from imbox.parser import fetch_email_by_uid
+from imbox.query import build_search_query
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class Messages:
+
+    folder_lookup = {}
+
+    def __init__(self,
+                 connection,
+                 parser_policy,
+                 **kwargs):
+
+        self.connection = connection
+        self.parser_policy = parser_policy
+        self.kwargs = kwargs
+        self._uid_list = self._query_uids(**kwargs)
+
+        logger.debug("Fetch all messages for UID in {}".format(self._uid_list))
+
+    def _fetch_email(self, uid):
+        return fetch_email_by_uid(uid=uid,
+                                  connection=self.connection,
+                                  parser_policy=self.parser_policy)
+
+    def _query_uids(self, **kwargs):
+        query_ = build_search_query(**kwargs)
+        message, data = self.connection.uid('search', None, query_)
+        if data[0] is None:
+            return []
+        return data[0].split()
+
+    def _fetch_email_list(self):
+        for uid in self._uid_list:
+            yield uid, self._fetch_email(uid)
+
+    def __repr__(self):
+        if len(self.kwargs) > 0:
+            return 'Messages({})'.format('\n'.join('{}={}'.format(key, value)
+                                                   for key, value in 
self.kwargs.items()))
+        return 'Messages(ALL)'
+
+    def __iter__(self):
+        return self._fetch_email_list()
+
+    def __next__(self):
+        return self
+
+    def __len__(self):
+        return len(self._uid_list)
+
+    def __getitem__(self, index):
+        uids = self._uid_list[index]
+
+        if not isinstance(uids, list):
+            uid = uids
+            return uid, self._fetch_email(uid)
+
+        return [(uid, self._fetch_email(uid))
+                for uid in uids]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox/parser.py 
new/imbox-0.9.6/imbox/parser.py
--- old/imbox-0.9.5/imbox/parser.py     2017-12-05 18:44:32.000000000 +0100
+++ new/imbox-0.9.6/imbox/parser.py     2018-08-14 17:22:47.000000000 +0200
@@ -1,14 +1,17 @@
+import imaplib
 import io
 import re
 import email
 import base64
 import quopri
+import sys
 import time
 from datetime import datetime
 from email.header import decode_header
 from imbox.utils import str_encode, str_decode
 
 import logging
+
 logger = logging.getLogger(__name__)
 
 
@@ -33,7 +36,10 @@
         return str_decode(str_encode(value, default_charset, 'replace'), 
default_charset)
     else:
         for index, (text, charset) in enumerate(headers):
-            logger.debug("Mail header no. {}: {} encoding {}".format(index, 
str_decode(text, charset or 'utf-8'), charset))
+            logger.debug("Mail header no. {index}: {data} encoding 
{charset}".format(
+                index=index,
+                data=str_decode(text, charset or 'utf-8', 'replace'),
+                charset=charset))
             try:
                 headers[index] = str_decode(text, charset or default_charset,
                                             'replace')
@@ -54,7 +60,7 @@
     for index, (address_name, address_email) in enumerate(addresses):
         addresses[index] = {'name': decode_mail_header(address_name),
                             'email': address_email}
-        logger.debug("{} Mail addressees in message: <{}> 
{}".format(header_name.upper(), address_name, address_email))
+        logger.debug("{} Mail address in message: <{}> 
{}".format(header_name.upper(), address_name, address_email))
     return addresses
 
 
@@ -63,7 +69,7 @@
     values = v.split('\n')
     value_results = []
     for value in values:
-        match = re.search(r'=\?((?:\w|-)+)\?(Q|B)\?(.+)\?=', value)
+        match = re.search(r'=\?((?:\w|-)+)\?([QB])\?(.+)\?=', value)
         if match:
             encoding, type_, code = match.groups()
             if type_ == 'Q':
@@ -120,10 +126,34 @@
     charset = message.get_content_charset('utf-8')
     try:
         return content.decode(charset, 'ignore')
+    except LookupError:
+        return content.decode(charset.replace("-", ""), 'ignore')
     except AttributeError:
         return content
 
 
+def fetch_email_by_uid(uid, connection, parser_policy):
+    message, data = connection.uid('fetch', uid, '(BODY.PEEK[] FLAGS)')
+    logger.debug("Fetched message for UID {}".format(int(uid)))
+
+    raw_headers, raw_email = data[0]
+
+    email_object = parse_email(raw_email, policy=parser_policy)
+    flags = parse_flags(raw_headers.decode())
+    email_object.__dict__['flags'] = flags
+
+    return email_object
+
+
+def parse_flags(headers):
+    """Copied from 
https://github.com/girishramnani/gmail/blob/master/gmail/message.py""";
+    if len(headers) == 0:
+        return []
+    if sys.version_info[0] == 3:
+        headers = bytes(headers, "ascii")
+    return list(imaplib.ParseFlags(headers))
+
+
 def parse_email(raw_email, policy=None):
     if isinstance(raw_email, bytes):
         raw_email = str_encode(raw_email, 'utf-8', errors='ignore')
@@ -137,9 +167,7 @@
     except UnicodeEncodeError:
         email_message = email.message_from_string(raw_email.encode('utf-8'), 
**email_parse_kwargs)
     maintype = email_message.get_content_maintype()
-    parsed_email = {}
-
-    parsed_email['raw_email'] = raw_email
+    parsed_email = {'raw_email': raw_email}
 
     body = {
         "plain": [],
@@ -159,7 +187,7 @@
                 content = decode_content(part)
 
             is_inline = content_disposition is None \
-                or content_disposition.startswith("inline")
+                        or content_disposition.startswith("inline")
             if content_type == "text/plain" and is_inline:
                 body['plain'].append(content)
             elif content_type == "text/html" and is_inline:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox/query.py 
new/imbox-0.9.6/imbox/query.py
--- old/imbox-0.9.5/imbox/query.py      2017-12-05 18:44:32.000000000 +0100
+++ new/imbox-0.9.6/imbox/query.py      2018-08-14 17:22:47.000000000 +0200
@@ -8,8 +8,7 @@
 def format_date(date):
     if isinstance(date, datetime.date):
         return date.strftime('%d-%b-%Y')
-    else:
-        return date
+    return date
 
 
 def build_search_query(**kwargs):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox/utils.py 
new/imbox-0.9.6/imbox/utils.py
--- old/imbox-0.9.5/imbox/utils.py      2017-09-18 10:12:35.000000000 +0200
+++ new/imbox-0.9.6/imbox/utils.py      2018-08-14 17:22:47.000000000 +0200
@@ -1,14 +1,16 @@
 import logging
 logger = logging.getLogger(__name__)
 
+
 def str_encode(value='', encoding=None, errors='strict'):
     logger.debug("Encode str {} with and errors {}".format(value, encoding, 
errors))
     return str(value, encoding, errors)
 
+
 def str_decode(value='', encoding=None, errors='strict'):
     if isinstance(value, str):
         return bytes(value, encoding, errors).decode('utf-8')
     elif isinstance(value, bytes):
         return value.decode(encoding or 'utf-8', errors=errors)
     else:
-        raise TypeError( "Cannot decode '{}' object".format(value.__class__) )
+        raise TypeError("Cannot decode '{}' object".format(value.__class__))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox/vendors/__init__.py 
new/imbox-0.9.6/imbox/vendors/__init__.py
--- old/imbox-0.9.5/imbox/vendors/__init__.py   1970-01-01 01:00:00.000000000 
+0100
+++ new/imbox-0.9.6/imbox/vendors/__init__.py   2018-08-14 17:22:47.000000000 
+0200
@@ -0,0 +1,11 @@
+from imbox.vendors.gmail import GmailMessages
+
+vendors = [GmailMessages]
+
+hostname_vendorname_dict = {vendor.hostname: vendor.name for vendor in vendors}
+name_authentication_string_dict = {vendor.name: 
vendor.authentication_error_message for vendor in vendors}
+
+__all__ = [v.__name__ for v in vendors]
+
+__all__ += ['hostname_vendorname_dict',
+            'name_authentication_string_dict']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox/vendors/gmail.py 
new/imbox-0.9.6/imbox/vendors/gmail.py
--- old/imbox-0.9.5/imbox/vendors/gmail.py      1970-01-01 01:00:00.000000000 
+0100
+++ new/imbox-0.9.6/imbox/vendors/gmail.py      2018-08-14 17:22:47.000000000 
+0200
@@ -0,0 +1,29 @@
+from imbox.messages import Messages
+
+
+class GmailMessages(Messages):
+    authentication_error_message = ('If you\'re not using an app-specific 
password, grab one here: '
+                                    
'https://myaccount.google.com/apppasswords')
+    hostname = 'imap.gmail.com'
+    name = 'gmail'
+    folder_lookup = {
+
+        'all_mail': '"[Gmail]/All Mail"',
+        'all': '"[Gmail]/All Mail"',
+        'all mail': '"[Gmail]/All Mail"',
+        'sent': '"[Gmail]/Sent Mail"',
+        'sent mail': '"[Gmail]/Sent Mail"',
+        'sent_mail': '"[Gmail]/Sent Mail"',
+        'drafts': '"[Gmail]/Drafts"',
+        'important': '"[Gmail]/Important"',
+        'spam': '"[Gmail]/Spam"',
+        'starred': '"[Gmail]/Starred"',
+        'trash': '"[Gmail]/Trash"',
+
+    }
+
+    def __init__(self,
+                 connection,
+                 parser_policy,
+                 **kwargs):
+        super().__init__(connection, parser_policy, **kwargs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox.egg-info/PKG-INFO 
new/imbox-0.9.6/imbox.egg-info/PKG-INFO
--- old/imbox-0.9.5/imbox.egg-info/PKG-INFO     2017-12-05 19:09:13.000000000 
+0100
+++ new/imbox-0.9.6/imbox.egg-info/PKG-INFO     2018-08-14 17:26:01.000000000 
+0200
@@ -1,12 +1,11 @@
 Metadata-Version: 1.1
 Name: imbox
-Version: 0.9.5
+Version: 0.9.6
 Summary: Python IMAP for Human beings
 Home-page: https://github.com/martinrusev/imbox
 Author: Martin Rusev
 Author-email: [email protected]
 License: MIT
-Description-Content-Type: UNKNOWN
 Description: Imbox - Python IMAP for Humans
         ==============================
         
@@ -45,36 +44,50 @@
                     ssl=True,
                     ssl_context=None,
                     starttls=False) as imbox:
+        
                 # Get all folders
                 status, folders_with_additional_info = imbox.folders()
         
-                # Gets all messages
-                all_messages = imbox.messages()
+                # Gets all messages from the inbox
+                all_inbox_messages = imbox.messages()
         
                 # Unread messages
-                unread_messages = imbox.messages(unread=True)
+                unread_inbox_messages = imbox.messages(unread=True)
+        
+                # Flagged messages
+                inbox_flagged_messages = imbox.messages(flagged=True)
+        
+                # Un-flagged messages
+                inbox_unflagged_messages = imbox.messages(unflagged=True)
+        
+                # Flagged messages
+                flagged_messages = imbox.messages(flagged=True)
+        
+                # Un-flagged messages
+                unflagged_messages = imbox.messages(unflagged=True)
         
                 # Messages sent FROM
-                messages_from = imbox.messages(sent_from='[email protected]')
+                inbox_messages_from = 
imbox.messages(sent_from='[email protected]')
         
                 # Messages sent TO
-                messages_from = imbox.messages(sent_to='[email protected]')
+                inbox_messages_to = 
imbox.messages(sent_to='[email protected]')
         
                 # Messages received before specific date
-                messages_from = imbox.messages(date__lt=datetime.date(2013, 7, 
31))
+                inbox_messages_received_before = 
imbox.messages(date__lt=datetime.date(2018, 7, 31))
         
                 # Messages received after specific date
-                messages_from = imbox.messages(date__gt=datetime.date(2013, 7, 
30))
+                inbox_messages_received_after = 
imbox.messages(date__gt=datetime.date(2018, 7, 30))
         
                 # Messages received on a specific date
-                messages_from = imbox.messages(date__on=datetime.date(2013, 7, 
30))
-        
-                # Messages from a specific folder
-                messages_folder = imbox.messages(folder='Social')
+                inbox_messages_received_on_date = 
imbox.messages(date__on=datetime.date(2018, 7, 30))
         
+                # Messages whose subjects contain a string
+                inbox_messages_subject_christmas = 
imbox.messages(subject='Christmas')
         
+                # Messages from a specific folder
+                messages_in_folder_social = imbox.messages(folder='Social')
         
-                for uid, message in all_messages:
+                for uid, message in all_inbox_messages:
                 # Every message is an object with the following keys
         
                     message.sent_from
@@ -134,7 +147,7 @@
         
                 # mark the message as read
                 imbox.mark_seen(uid)
-                
+        
         
         
         Changelog
@@ -167,3 +180,4 @@
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox.egg-info/SOURCES.txt 
new/imbox-0.9.6/imbox.egg-info/SOURCES.txt
--- old/imbox-0.9.5/imbox.egg-info/SOURCES.txt  2017-12-05 19:09:13.000000000 
+0100
+++ new/imbox-0.9.6/imbox.egg-info/SOURCES.txt  2018-08-14 17:26:01.000000000 
+0200
@@ -5,6 +5,8 @@
 setup.py
 imbox/__init__.py
 imbox/imap.py
+imbox/imbox.py
+imbox/messages.py
 imbox/parser.py
 imbox/query.py
 imbox/utils.py
@@ -12,12 +14,10 @@
 imbox.egg-info/SOURCES.txt
 imbox.egg-info/dependency_links.txt
 imbox.egg-info/not-zip-safe
-imbox.egg-info/pbr.json
 imbox.egg-info/top_level.txt
+imbox/vendors/__init__.py
+imbox/vendors/gmail.py
 tests/8422.msg
 tests/__init__.py
 tests/parser_tests.py
-tests/query_tests.py
-tests/__pycache__/__init__.cpython-35.pyc
-tests/__pycache__/parser_tests.cpython-35.pyc
-tests/__pycache__/query_tests.cpython-35.pyc
\ No newline at end of file
+tests/query_tests.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/imbox.egg-info/pbr.json 
new/imbox-0.9.6/imbox.egg-info/pbr.json
--- old/imbox-0.9.5/imbox.egg-info/pbr.json     2016-06-08 08:38:41.000000000 
+0200
+++ new/imbox-0.9.6/imbox.egg-info/pbr.json     1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-{"is_release": false, "git_version": "64c06c1"}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/setup.py new/imbox-0.9.6/setup.py
--- old/imbox-0.9.5/setup.py    2017-12-05 19:08:52.000000000 +0100
+++ new/imbox-0.9.6/setup.py    2018-08-14 17:22:47.000000000 +0200
@@ -1,7 +1,9 @@
 from setuptools import setup
 import os
 
-version = '0.9.5'
+import imbox
+
+version = imbox.__version__
 
 
 def read(filename):
@@ -17,7 +19,7 @@
     author_email='[email protected]',
     url='https://github.com/martinrusev/imbox',
     license='MIT',
-    packages=['imbox'],
+    packages=['imbox', 'imbox.vendors'],
     package_dir={'imbox': 'imbox'},
     zip_safe=False,
     classifiers=(
@@ -25,7 +27,8 @@
         'Programming Language :: Python :: 3.3',
         'Programming Language :: Python :: 3.4',
         'Programming Language :: Python :: 3.5',
-        'Programming Language :: Python :: 3.6'
+        'Programming Language :: Python :: 3.6',
+        'Programming Language :: Python :: 3.7',
     ),
     test_suite='tests',
 )
Binary files old/imbox-0.9.5/tests/__pycache__/__init__.cpython-35.pyc and 
new/imbox-0.9.6/tests/__pycache__/__init__.cpython-35.pyc differ
Binary files old/imbox-0.9.5/tests/__pycache__/parser_tests.cpython-35.pyc and 
new/imbox-0.9.6/tests/__pycache__/parser_tests.cpython-35.pyc differ
Binary files old/imbox-0.9.5/tests/__pycache__/query_tests.cpython-35.pyc and 
new/imbox-0.9.6/tests/__pycache__/query_tests.cpython-35.pyc differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imbox-0.9.5/tests/parser_tests.py 
new/imbox-0.9.6/tests/parser_tests.py
--- old/imbox-0.9.5/tests/parser_tests.py       2017-12-05 18:44:32.000000000 
+0100
+++ new/imbox-0.9.6/tests/parser_tests.py       2018-08-14 17:22:47.000000000 
+0200
@@ -274,6 +274,44 @@
 --____NOIBTUQXSYRVOOAFLCHY____--
 """
 
+raw_email_encoded_encoding_charset_contains_a_minus = b"""Delivered-To: 
<[email protected]>
+Return-Path: <[email protected]>
+Message-ID: <74836CF6FF9B1965927DE7EE8A087483@NXOFGRQFQW2>
+From: <[email protected]>
+To: <[email protected]>
+Subject: Salut, mon cher.
+Date: 30 May 2018 22:47:37 +0200
+MIME-Version: 1.0
+Content-Type: multipart/alternative;
+       boundary="----=_NextPart_000_0038_01D3F85C.02934C4A"
+
+------=_NextPart_000_0038_01D3F85C.02934C4A
+Content-Type: text/plain;
+       charset="cp-850"
+Content-Transfer-Encoding: quoted-printable
+
+spam here
+
+
+cliquez ici
+------=_NextPart_000_0038_01D3F85C.02934C4A
+Content-Type: text/html;
+       charset="cp-850"
+Content-Transfer-Encoding: quoted-printable
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML><HEAD>
+<META http-equiv=3DContent-Type content=3D"text/html; charset=3Dcp-850">
+<META content=3D"MSHTML 6.00.2900.2456" name=3DGENERATOR>
+<STYLE></STYLE>
+</HEAD>
+<BODY bgColor=3D#ffffff>
+spam here<br>
+<br>
+<a href=3D"http://spammer-url";><b>cliquez =
+ici</b></a></br></BODY></HTML>
+------=_NextPart_000_0038_01D3F85C.02934C4A--
+"""
 
 class TestParser(unittest.TestCase):
 
@@ -324,6 +362,12 @@
         self.assertEqual('abc.xyz', attachment['filename'])
         self.assertTrue(attachment['content'])
 
+    def 
test_parse_email_accept_if_declared_charset_contains_a_minus_character(self):
+        parsed_email = 
parse_email(raw_email_encoded_encoding_charset_contains_a_minus)
+        self.assertEqual("Salut, mon cher.", parsed_email.subject)
+        self.assertTrue(parsed_email.body['plain'])
+        self.assertTrue(parsed_email.body['html'])
+
     # TODO - Complete the test suite
     def test_decode_mail_header(self):
         pass
@@ -336,6 +380,9 @@
         from_message_object = email.message_from_string("From: John Smith 
<[email protected]>")
         self.assertEqual([{'email': '[email protected]', 'name': 'John 
Smith'}], get_mail_addresses(from_message_object, 'from'))
 
+        invalid_encoding_in_from_message_object = 
email.message_from_string("From: =?UTF-8?Q?C=E4cilia?= 
<[email protected]>")
+        self.assertEqual([{'email': '[email protected]', 'name': 
'C�cilia'}], get_mail_addresses(invalid_encoding_in_from_message_object, 
'from'))
+
     def test_parse_email_with_policy(self):
         if not SMTP:
             return


Reply via email to