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 - sebix+novell.com@sebix.at
+
+- 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: martin@amon.cx
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='martin@amon.cx')
+ inbox_messages_from = imbox.messages(sent_from='sender@example.org')
# Messages sent TO
- messages_from = imbox.messages(sent_to='martin@amon.cx')
+ inbox_messages_to = imbox.messages(sent_to='receiver@example.org')
# 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='martin@amon.cx')
+ inbox_messages_from = imbox.messages(sent_from='sender@example.org')
# Messages sent TO
- messages_from = imbox.messages(sent_to='martin@amon.cx')
+ inbox_messages_to = imbox.messages(sent_to='receiver@example.org')
# 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: martin@amon.cx
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='martin@amon.cx')
+ inbox_messages_from = imbox.messages(sent_from='sender@example.org')
# Messages sent TO
- messages_from = imbox.messages(sent_to='martin@amon.cx')
+ inbox_messages_to = imbox.messages(sent_to='receiver@example.org')
# 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='martin@amon.cx',
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: