diff options
author | syt <syt@localhost.localdomain> | 2006-09-05 13:36:23 +0200 |
---|---|---|
committer | syt <syt@localhost.localdomain> | 2006-09-05 13:36:23 +0200 |
commit | 59061b4d3bcab97ecce52bbb1688264ce8b83926 (patch) | |
tree | f093400a4cdc62cd55e5991a44f21ea65f6c2eb1 | |
parent | 83b568c1e69278f4a5d0bf855ec9aa718d0d6a96 (diff) | |
download | logilab-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-- | ChangeLog | 4 | ||||
-rw-r--r-- | testlib.py | 2 | ||||
-rw-r--r-- | umessage.py | 112 |
3 files changed, 116 insertions, 2 deletions
@@ -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 @@ -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 + + + + |