14 |
18 |
15 RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]""" |
19 RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]""" |
16 |
20 |
17 |
21 |
18 class EmailAddress(object): |
22 class EmailAddress(object): |
19 __slots__ = ('_localpart', '_domainname') |
23 """Simple class for validated e-mail addresses.""" |
|
24 __slots__ = ('localpart', 'domainname') |
20 |
25 |
21 def __init__(self, address): |
26 def __init__(self, address): |
|
27 """Creates a new instance from the string/unicode ``address``.""" |
22 if not isinstance(address, basestring): |
28 if not isinstance(address, basestring): |
23 raise TypeError('address is not a str/unicode object: %r' % |
29 raise TypeError('address is not a str/unicode object: %r' % |
24 address) |
30 address) |
25 self._localpart = None |
31 self.localpart = None |
26 self._domainname = None |
32 self.domainname = None |
27 self.__chkAddress(address) |
33 self._chk_address(address) |
28 |
34 |
29 def __eq__(self, other): |
35 def __eq__(self, other): |
30 if isinstance(other, self.__class__): |
36 if isinstance(other, self.__class__): |
31 return self._localpart == other._localpart and \ |
37 return self.localpart == other.localpart and \ |
32 self._domainname == other._domainname |
38 self.domainname == other.domainname |
33 return NotImplemented |
39 return NotImplemented |
34 |
40 |
35 def __ne__(self, other): |
41 def __ne__(self, other): |
36 if isinstance(other, self.__class__): |
42 if isinstance(other, self.__class__): |
37 return self._localpart != other._localpart or \ |
43 return self.localpart != other.localpart or \ |
38 self._domainname != other._domainname |
44 self.domainname != other.domainname |
39 return NotImplemented |
45 return NotImplemented |
40 |
46 |
41 def __repr__(self): |
47 def __repr__(self): |
42 return "EmailAddress('%s@%s')" % (self._localpart, self._domainname) |
48 return "EmailAddress('%s@%s')" % (self.localpart, self.domainname) |
43 |
49 |
44 def __str__(self): |
50 def __str__(self): |
45 return "%s@%s" % (self._localpart, self._domainname) |
51 return "%s@%s" % (self.localpart, self.domainname) |
46 |
52 |
47 def __chkAddress(self, address): |
53 def _chk_address(self, address): |
|
54 """Checks if the string ``address`` could be used for an e-mail |
|
55 address.""" |
48 parts = address.split('@') |
56 parts = address.split('@') |
49 p_len = len(parts) |
57 p_len = len(parts) |
50 if p_len is 2: |
58 if p_len is 2: |
51 self._localpart = self.__chkLocalpart(parts[0]) |
59 self.localpart = check_localpart(parts[0]) |
52 if len(parts[1]) > 0: |
60 if len(parts[1]) > 0: |
53 self._domainname = chk_domainname(parts[1]) |
61 self.domainname = chk_domainname(parts[1]) |
54 else: |
62 else: |
55 raise VMMEAE(_(u"Missing domain name after “%s@”.") % |
63 raise VMMEAE(_(u"Missing domain name after “%s@”.") % |
56 self._localpart, DOMAIN_NO_NAME) |
64 self.localpart, DOMAIN_NO_NAME) |
57 elif p_len < 2: |
65 elif p_len < 2: |
58 raise VMMEAE(_(u"Missing '@' sign in e-mail address “%s”.") % |
66 raise VMMEAE(_(u"Missing '@' sign in e-mail address “%s”.") % |
59 address, INVALID_ADDRESS) |
67 address, INVALID_ADDRESS) |
60 elif p_len > 2: |
68 elif p_len > 2: |
61 raise VMMEAE(_(u"Too many '@' signs in e-mail address “%s”.") % |
69 raise VMMEAE(_(u"Too many '@' signs in e-mail address “%s”.") % |
62 address, INVALID_ADDRESS) |
70 address, INVALID_ADDRESS) |
63 |
71 |
64 def __chkLocalpart(self, localpart): |
|
65 """Validates the local-part of an e-mail address. |
|
66 |
72 |
67 Arguments: |
73 _ = lambda msg: msg |
68 localpart -- local-part of the e-mail address that should be validated |
74 |
69 """ |
75 |
70 if len(localpart) < 1: |
76 def check_localpart(localpart): |
71 raise VMMEAE(_(u'No local-part specified.'), LOCALPART_INVALID) |
77 """Validates the local-part of an e-mail address. |
72 if len(localpart) > 64: |
78 |
73 raise VMMEAE(_(u'The local-part “%s” is too long') % localpart, |
79 Argument: |
74 LOCALPART_TOO_LONG) |
80 localpart -- local-part of the e-mail address that should be validated |
75 ic = set(re.findall(RE_LOCALPART, localpart)) |
81 """ |
76 if len(ic): |
82 if len(localpart) < 1: |
77 ichrs = u''.join((u'“%s” ' % c for c in ic)) |
83 raise VMMEAE(_(u'No local-part specified.'), LOCALPART_INVALID) |
78 raise VMMEAE(_(u"The local-part “%(lpart)s” contains invalid\ |
84 if len(localpart) > 64: |
79 characters: %(ichrs)s") % {'lpart': localpart, 'ichrs': ichrs}, |
85 raise VMMEAE(_(u'The local-part “%s” is too long') % localpart, |
80 LOCALPART_INVALID) |
86 LOCALPART_TOO_LONG) |
81 return localpart |
87 invalid_chars = set(re.findall(RE_LOCALPART, localpart)) |
|
88 if invalid_chars: |
|
89 i_chrs = u''.join((u'“%s” ' % c for c in invalid_chars)) |
|
90 raise VMMEAE(_(u"The local-part “%(l_part)s” contains invalid\ |
|
91 characters: %(i_chrs)s") % {'l_part': localpart, 'i_chrs': i_chrs}, |
|
92 LOCALPART_INVALID) |
|
93 return localpart |
|
94 |
|
95 del _ |