summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyt <syt@localhost.localdomain>2006-09-05 13:36:23 +0200
committersyt <syt@localhost.localdomain>2006-09-05 13:36:23 +0200
commit59061b4d3bcab97ecce52bbb1688264ce8b83926 (patch)
treef093400a4cdc62cd55e5991a44f21ea65f6c2eb1
parent83b568c1e69278f4a5d0bf855ec9aa718d0d6a96 (diff)
downloadlogilab-common-59061b4d3bcab97ecce52bbb1688264ce8b83926.tar.gz
From Sylvain.Thenault@logilab.fr Tue Sep 5 10:25:33 2006
Return-Path: <Sylvain.Thenault@logilab.fr> X-Original-To: adim@logilab.fr Delivered-To: adim@logilab.fr Received: from tucana.logilab.fr (tucana.logilab.fr [172.17.0.4]) by orion.logilab.fr (Postfix) with ESMTP id B9BF0EA9FF for <adim@logilab.fr>; Tue, 5 Sep 2006 10:25:33 +0200 (CEST) Received: from smtp1-g19.free.fr (smtp1-g19.free.fr [212.27.42.27]) by tucana.logilab.fr (Postfix) with ESMTP id A751571403E for <adim@logilab.fr>; Tue, 5 Sep 2006 10:25:50 +0200 (CEST) Received: from localhost.localdomain (ram31-2-82-228-88-123.fbx.proxad.net [82.228.88.123]) by smtp1-g19.free.fr (Postfix) with ESMTP id 670B090E2E for <adim@logilab.fr>; Tue, 5 Sep 2006 10:25:45 +0200 (CEST) Content-Type: multipart/mixed; boundary="===============0640966485==" MIME-Version: 1.0 Message-Id: <patchbomb.1157444811@localhost.localdomain> Date: Tue, 5 Sep 2006 10:26:51 +0200 To: adim@logilab.fr X-Spambayes-Classification: ham; 0.02 Status: RO X-Status: F Content-Length: 160 Lines: 8 --===============0640966485== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit --===============0640966485==-- From Sylvain.Thenault@logilab.fr Tue Sep 5 10:25:34 2006 Return-Path: <Sylvain.Thenault@logilab.fr> X-Original-To: adim@logilab.fr Delivered-To: adim@logilab.fr Received: from tucana.logilab.fr (tucana.logilab.fr [172.17.0.4]) by orion.logilab.fr (Postfix) with ESMTP id 08C46EAA65 for <adim@logilab.fr>; Tue, 5 Sep 2006 10:25:34 +0200 (CEST) Received: from smtp1-g19.free.fr (smtp1-g19.free.fr [212.27.42.27]) by tucana.logilab.fr (Postfix) with ESMTP id EBF277143EE for <adim@logilab.fr>; Tue, 5 Sep 2006 10:25:50 +0200 (CEST) Received: from localhost.localdomain (ram31-2-82-228-88-123.fbx.proxad.net [82.228.88.123]) by smtp1-g19.free.fr (Postfix) with ESMTP id 744699A992 for <adim@logilab.fr>; Tue, 5 Sep 2006 10:25:46 +0200 (CEST) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [PATCH 1 of 2] blabla X-Mercurial-Node: c9a40d354365f82164a6c0ffcf9c80deb644e0d5 Message-Id: <c9a40d354365f82164a6.1157444812@localhost.localdomain> In-Reply-To: <patchbomb.1157444811@localhost.localdomain> Date: Tue, 5 Sep 2006 10:26:52 +0200 From: syt@logilab.fr To: adim@logilab.fr X-Spambayes-Classification: ham; 0.00 Status: RO X-Status: F Content-Length: 510 Lines: 17 blabla
-rw-r--r--ChangeLog4
-rw-r--r--testlib.py2
-rw-r--r--umessage.py112
3 files changed, 116 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index e27fe72..4c1569c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,9 +2,11 @@ ChangeLog for logilab.common
============================
--
- * new "date" otion type in optik_ext
+ * new umessage module which provides a class similar to the standard
+ email.Message class but returning unicode strings
* new clcommands module to handle commands based command line tool
(based on the configuration module)
+ * new "date" otion type in optik_ext
* new AttrObject in testlib to create objects in test with arbitrary attributes
* add pytest to run project's tests and get rid of all runtests.py
* add pytest option to enable design-by-contract using aspects
diff --git a/testlib.py b/testlib.py
index b69359f..dba29f6 100644
--- a/testlib.py
+++ b/testlib.py
@@ -1063,6 +1063,6 @@ def enable_dbc(*args):
return True
-class AttrObject:
+class AttrObject: # XXX cf mock_object
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
diff --git a/umessage.py b/umessage.py
new file mode 100644
index 0000000..a42cb40
--- /dev/null
+++ b/umessage.py
@@ -0,0 +1,112 @@
+"""unicode email support"""
+
+import email
+from email.Utils import parseaddr, parsedate
+from email.Header import decode_header
+
+from mx.DateTime import DateTime
+
+def decode_QP(string):
+ parts = []
+ for decoded, charset in decode_header(string):
+ if charset is None:
+ charset = 'iso-8859-15'
+ parts.append(unicode(decoded, charset))
+
+ return u' '.join(parts)
+
+def message_from_file(fd):
+ try:
+ return UMessage(email.message_from_file(fd))
+ except email.Errors.MessageParseError:
+ return ''
+
+class UMessage:
+ """Encapsulates an email.Message instance and returns only unicode objects"""
+
+ def __init__(self, message):
+ self.message = message
+
+ # email.Message interface #################################################
+
+ def get(self, header, default=None):
+ value = self.message.get(header, default)
+ if value:
+ return decode_QP(value)
+ return value
+
+ def get_all(self, header, default=None):
+ return [decode_QP(val) for val in self.message.get_all(header, default)
+ if val is not None]
+
+ def get_payload(self, index=None, decode=False):
+ message = self.message
+ if index is None:
+ payload = message.get_payload(index, decode)
+ if isinstance(payload, list):
+ return [UMessage(msg) for msg in payload]
+ if message.get_content_maintype() != 'text':
+ return payload
+ return unicode(payload or '', message.get_charset() or 'iso-8859-15')
+ else:
+ payload = UMessage(message.get_payload(index, decode))
+ return payload
+
+ def is_multipart(self):
+ return self.message.is_multipart()
+
+ def get_boundary(self):
+ return self.message.get_boundary()
+
+ def walk(self):
+ for part in self.message.walk():
+ yield UMessage(part)
+
+ def get_content_maintype(self):
+ return unicode(self.message.get_content_maintype())
+
+ def get_content_type(self):
+ return unicode(self.message.get_content_type())
+
+ def get_filename(self, failobj=None):
+ value = self.message.get_filename(failobj)
+ if value is failobj:
+ return value
+ try:
+ return unicode(value)
+ except UnicodeDecodeError:
+ return u'error decoding filename'
+
+ # other convenience methods ###############################################
+
+ def headers(self):
+ """return an unicode string containing all the message's headers"""
+ values = []
+ for header in self.message.keys():
+ values.append(u'%s: %s' % (header, self.get(header)))
+ return '\n'.join(values)
+
+ def multi_addrs(self, header):
+ """return a list of 2-uple (name, address) for the given address (which
+ is exepected to be an header containing address such as from, to, cc...)
+ """
+ persons = []
+ for person in self.get_all(header, ()):
+ name, mail = parseaddr(person)
+ persons.append((name, mail))
+ return persons
+
+ def date(self):
+ """return a mx.DateTime object for the email's date or None if no date is
+ set or if it can't be parsed
+ """
+ value = self.get('date')
+ if value:
+ datetuple = parsedate(value)
+ if datetuple:
+ return DateTime(*datetuple[:6])
+ return None
+
+
+
+