def reverse(self, lookup_view, *args, **kwargs): if args and kwargs: raise ValueError("Don't mix *args and **kwargs in call to reverse()!") try: lookup_view = get_callable(lookup_view, True) except (ImportError, AttributeError) as e: raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e)) possibilities = self.reverse_dict.getlist(lookup_view) for possibility, pattern in possibilities: for result, params in possibility: if args: if len(args) != len(params): continue unicode_args = [force_unicode(val) for val in args] candidate = result % dict(list(zip(params, unicode_args))) else: if set(kwargs.keys()) != set(params): continue unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in list(kwargs.items())]) candidate = result % unicode_kwargs if re.search('^%s' % pattern, candidate, re.UNICODE): return candidate # lookup_view can be URL label, or dotted path, or callable, Any of # these can be passed in at the top, but callables are not friendly in # error messages. m = getattr(lookup_view, '__module__', None) n = getattr(lookup_view, '__name__', None) if m is not None and n is not None: lookup_view_s = "%s.%s" % (m, n) else: lookup_view_s = lookup_view raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword " "arguments '%s' not found." % (lookup_view_s, args, kwargs))
def add_item(self, title, link, description, author_email=None, author_name=None, author_link=None, pubdate=None, comments=None, unique_id=None, enclosure=None, categories=(), item_copyright=None, ttl=None, **kwargs): """ Adds an item to the feed. All args are expected to be Python Unicode objects except pubdate, which is a datetime.datetime object, and enclosure, which is an instance of the Enclosure class. """ to_unicode = lambda s: force_unicode(s, strings_only=True) if categories: categories = [to_unicode(c) for c in categories] if ttl is not None: # Force ints to unicode ttl = force_unicode(ttl) item = { 'title': to_unicode(title), 'link': iri_to_uri(link), 'description': to_unicode(description), 'author_email': to_unicode(author_email), 'author_name': to_unicode(author_name), 'author_link': iri_to_uri(author_link), 'pubdate': pubdate, 'comments': to_unicode(comments), 'unique_id': to_unicode(unique_id), 'enclosure': enclosure, 'categories': categories or (), 'item_copyright': to_unicode(item_copyright), 'ttl': ttl, } item.update(kwargs) self.items.append(item)
def __init__(self, title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs): to_unicode = lambda s: force_unicode(s, strings_only=True) if categories: categories = [force_unicode(c) for c in categories] if ttl is not None: # Force ints to unicode ttl = force_unicode(ttl) self.feed = { 'title': to_unicode(title), 'link': iri_to_uri(link), 'description': to_unicode(description), 'language': to_unicode(language), 'author_email': to_unicode(author_email), 'author_name': to_unicode(author_name), 'author_link': iri_to_uri(author_link), 'subtitle': to_unicode(subtitle), 'categories': categories or (), 'feed_url': iri_to_uri(feed_url), 'feed_copyright': to_unicode(feed_copyright), 'id': feed_guid or link, 'ttl': ttl, } self.feed.update(kwargs) self.items = []
def format(self, formatstr): pieces = [] for i, piece in enumerate(re_formatchars.split(force_unicode(formatstr))): if i % 2: pieces.append(force_unicode(getattr(self, piece)())) elif piece: pieces.append(re_escaped.sub(r'\1', piece)) return ''.join(pieces)
def _helper(list_, tabs=1): indent = '\t' * tabs output = [] list_length = len(list_) i = 0 while i < list_length: title = list_[i] sublist = '' sublist_item = None if isinstance(title, (list, tuple)): sublist_item = title title = '' elif i < list_length - 1: next_item = list_[i+1] if next_item and isinstance(next_item, (list, tuple)): # The next item is a sub-list. sublist_item = next_item # We've processed the next item now too. i += 1 if sublist_item: sublist = _helper(sublist_item, tabs+1) sublist = '\n%s<ul>\n%s\n%s</ul>\n%s' % (indent, sublist, indent, indent) output.append('%s<li>%s%s</li>' % (indent, escaper(force_unicode(title)), sublist)) i += 1 return '\n'.join(output)
def safeseq(value): """ A "safe" filter for sequences. Marks each element in the sequence, individually, as safe, after converting them to unicode. Returns a list with the results. """ return [mark_safe(force_unicode(obj)) for obj in value]
def _dec(*args, **kwargs): if args: args = list(args) args[0] = force_unicode(args[0]) if isinstance(args[0], SafeData) and getattr(func, 'is_safe', False): return mark_safe(func(*args, **kwargs)) return func(*args, **kwargs)
def wrap(text, width): """ A word-wrap function that preserves existing line breaks and most spaces in the text. Expects that existing line breaks are posix newlines. """ text = force_unicode(text) def _generator(): it = iter(text.split(' ')) word = next(it) yield word pos = len(word) - word.rfind('\n') - 1 for word in it: if "\n" in word: lines = word.split('\n') else: lines = (word,) pos += len(lines[0]) + 1 if pos > width: yield '\n' pos = len(lines[-1]) else: yield ' ' if len(lines) > 1: pos = len(lines[-1]) yield word return ''.join(_generator())
def pprint(value): """A wrapper around pprint.pprint -- for debugging, really.""" from pprint import pformat try: return pformat(value) except Exception, e: return u"Error in formatting: %s" % force_unicode(e, errors="replace")
def wrap(text, width): """ A word-wrap function that preserves existing line breaks and most spaces in the text. Expects that existing line breaks are posix newlines. """ text = force_unicode(text) def _generator(): it = iter(text.split(' ')) word = next(it) yield word pos = len(word) - word.rfind('\n') - 1 for word in it: if "\n" in word: lines = word.split('\n') else: lines = (word, ) pos += len(lines[0]) + 1 if pos > width: yield '\n' pos = len(lines[-1]) else: yield ' ' if len(lines) > 1: pos = len(lines[-1]) yield word return ''.join(_generator())
def _helper(list_, tabs=1): indent = u'\t' * tabs output = [] list_length = len(list_) i = 0 while i < list_length: title = list_[i] sublist = '' sublist_item = None if isinstance(title, (list, tuple)): sublist_item = title title = '' elif i < list_length - 1: next_item = list_[i + 1] if next_item and isinstance(next_item, (list, tuple)): # The next item is a sub-list. sublist_item = next_item # We've processed the next item now too. i += 1 if sublist_item: sublist = _helper(sublist_item, tabs + 1) sublist = '\n%s<ul>\n%s\n%s</ul>\n%s' % (indent, sublist, indent, indent) output.append('%s<li>%s%s</li>' % (indent, escaper(force_unicode(title)), sublist)) i += 1 return '\n'.join(output)
def escape(html): """ Returns the given HTML with ampersands, quotes and angle brackets encoded. """ return mark_safe( force_unicode(html).replace('&', '&').replace('<', '<').replace( '>', '>').replace('"', '"').replace("'", '''))
def clean_html(text): """ Clean the given HTML. Specifically, do the following: * Convert <b> and <i> to <strong> and <em>. * Encode all ampersands correctly. * Remove all "target" attributes from <a> tags. * Remove extraneous HTML, such as presentational tags that open and immediately close and <br clear="all">. * Convert hard-coded bullets into HTML unordered lists. * Remove stuff like "<p> </p>", but only if it's at the bottom of the text. """ from google.appengine._internal.django.utils.text import normalize_newlines text = normalize_newlines(force_unicode(text)) text = re.sub(r'<(/?)\s*b\s*>', '<\\1strong>', text) text = re.sub(r'<(/?)\s*i\s*>', '<\\1em>', text) text = fix_ampersands(text) # Remove all target="" attributes from <a> tags. text = link_target_attribute_re.sub('\\1', text) # Trim stupid HTML such as <br clear="all">. text = html_gunk_re.sub('', text) # Convert hard-coded bullets into HTML unordered lists. def replace_p_tags(match): s = match.group().replace('</p>', '</li>') for d in DOTS: s = s.replace('<p>%s' % d, '<li>') return '<ul>\n%s\n</ul>' % s text = hard_coded_bullets_re.sub(replace_p_tags, text) # Remove stuff like "<p> </p>", but only if it's at the bottom # of the text. text = trailing_empty_content_re.sub('', text) return text
def pprint(value): """A wrapper around pprint.pprint -- for debugging, really.""" from pprint import pformat try: return pformat(value) except Exception as e: return "Error in formatting: %s" % force_unicode(e, errors="replace")
def get_text_list(list_, last_word=ugettext_lazy('or')): """ >>> get_text_list(['a', 'b', 'c', 'd']) u'a, b, c or d' >>> get_text_list(['a', 'b', 'c'], 'and') u'a, b and c' >>> get_text_list(['a', 'b'], 'and') u'a and b' >>> get_text_list(['a']) u'a' >>> get_text_list([]) u'' """ if len(list_) == 0: return '' if len(list_) == 1: return force_unicode(list_[0]) return '%s %s %s' % (', '.join([force_unicode(i) for i in list_][:-1]), force_unicode(last_word), force_unicode(list_[-1]))
def urlquote_plus(url, safe=''): """ A version of Python's urllib.quote_plus() function that can operate on unicode strings. The url is first UTF-8 encoded before quoting. The returned string can safely be used as part of an argument to a subsequent iri_to_uri() call without double-quoting occurring. """ return force_unicode(urllib.quote_plus(smart_str(url), safe))
def render(self, context): bits = [] for node in self: if isinstance(node, Node): bits.append(self.render_node(node, context)) else: bits.append(node) return mark_safe(''.join([force_unicode(b) for b in bits]))
def urlquote_plus(url, safe=''): """ A version of Python's urllib.quote_plus() function that can operate on unicode strings. The url is first UTF-8 encoded before quoting. The returned string can safely be used as part of an argument to a subsequent iri_to_uri() call without double-quoting occurring. """ return force_unicode(urllib.parse.quote_plus(smart_str(url), safe))
def render(self, context): try: output = self.filter_expression.resolve(context) output = localize(output) output = force_unicode(output) except TemplateSyntaxError, e: if not hasattr(e, 'source'): e.source = self.source raise
def linebreaks(value, autoescape=False): """Converts newlines into <p> and <br />s.""" value = re.sub(r'\r\n|\r|\n', '\n', force_unicode(value)) # normalize newlines paras = re.split('\n{2,}', value) if autoescape: paras = ['<p>%s</p>' % escape(p).replace('\n', '<br />') for p in paras] else: paras = ['<p>%s</p>' % p.replace('\n', '<br />') for p in paras] return '\n\n'.join(paras)
def __init__(self, message, code=None, params=None): import operator from google.appengine._internal.django.utils.encoding import force_unicode """ ValidationError can be passed any object that can be printed (usually a string), a list of objects or a dictionary. """ if isinstance(message, dict): self.message_dict = message # Reduce each list of messages into a single list. message = reduce(operator.add, message.values()) if isinstance(message, list): self.messages = [force_unicode(msg) for msg in message] else: self.code = code self.params = params message = force_unicode(message) self.messages = [message]
def get_valid_filename(s): """ Returns the given string converted to a string that can be used for a clean filename. Specifically, leading and trailing spaces are removed; other spaces are converted to underscores; and anything that is not a unicode alphanumeric, dash, underscore, or dot, is removed. >>> get_valid_filename("john's portrait in 2004.jpg") u'johns_portrait_in_2004.jpg' """ s = force_unicode(s).strip().replace(' ', '_') return re.sub(r'(?u)[^-\w.]', '', s)
def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False): """ Converts any URLs in text into clickable links. Works on http://, https://, www. links and links ending in .org, .net or .com. Links can have trailing punctuation (periods, commas, close-parens) and leading punctuation (opening parens) and it'll still do the right thing. If trim_url_limit is not None, the URLs in link text longer than this limit will truncated to trim_url_limit-3 characters and appended with an elipsis. If nofollow is True, the URLs in link text will get a rel="nofollow" attribute. If autoescape is True, the link text and URLs will get autoescaped. """ trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x safe_input = isinstance(text, SafeData) words = word_split_re.split(force_unicode(text)) nofollow_attr = nofollow and ' rel="nofollow"' or '' for i, word in enumerate(words): match = None if '.' in word or '@' in word or ':' in word: match = punctuation_re.match(word) if match: lead, middle, trail = match.groups() # Make URL we want to point to. url = None if middle.startswith('http://') or middle.startswith('https://'): url = urlquote(middle, safe='/&=:;#?+*') elif middle.startswith('www.') or ('@' not in middle and middle and middle[0] in string.ascii_letters + string.digits and (middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))): url = urlquote('http://%s' % middle, safe='/&=:;#?+*') elif '@' in middle and not ':' in middle and simple_email_re.match(middle): url = 'mailto:%s' % middle nofollow_attr = '' # Make link. if url: trimmed = trim_url(middle) if autoescape and not safe_input: lead, trail = escape(lead), escape(trail) url, trimmed = escape(url), escape(trimmed) middle = '<a href="%s"%s>%s</a>' % (url, nofollow_attr, trimmed) words[i] = mark_safe('%s%s%s' % (lead, middle, trail)) else: if safe_input: words[i] = mark_safe(word) elif autoescape: words[i] = escape(word) elif safe_input: words[i] = mark_safe(word) elif autoescape: words[i] = escape(word) return ''.join(words)
def _render_value_in_context(value, context): """ Converts any value to a string to become part of a rendered template. This means escaping, if required, and conversion to a unicode object. If value is a string, it is expected to have already been translated. """ value = localize(value) value = force_unicode(value) if (context.autoescape and not isinstance(value, SafeData)) or isinstance(value, EscapeData): return escape(value) else: return value
def __init__( self, title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs ): to_unicode = lambda s: force_unicode(s, strings_only=True) if categories: categories = [force_unicode(c) for c in categories] if ttl is not None: # Force ints to unicode ttl = force_unicode(ttl) self.feed = { "title": to_unicode(title), "link": iri_to_uri(link), "description": to_unicode(description), "language": to_unicode(language), "author_email": to_unicode(author_email), "author_name": to_unicode(author_name), "author_link": iri_to_uri(author_link), "subtitle": to_unicode(subtitle), "categories": categories or (), "feed_url": iri_to_uri(feed_url), "feed_copyright": to_unicode(feed_copyright), "id": feed_guid or link, "ttl": ttl, } self.feed.update(kwargs) self.items = []
def safe_join(base, *paths): """ Joins one or more path components to the base path component intelligently. Returns a normalized, absolute version of the final path. The final path must be located inside of the base path component (otherwise a ValueError is raised). """ # We need to use normcase to ensure we don't false-negative on case # insensitive operating systems (like Windows). base = force_unicode(base) paths = [force_unicode(p) for p in paths] final_path = normcase(abspathu(join(base, *paths))) base_path = normcase(abspathu(base)) base_path_len = len(base_path) # Ensure final_path starts with base_path and that the next character after # the final path is os.sep (or nothing, in which case final_path must be # equal to base_path). if not final_path.startswith(base_path) or final_path[base_path_len:base_path_len+1] not in ('', sep): raise ValueError('the joined path is located outside of the base path' ' component') return final_path
def __init__(self, req): self._req = req # FIXME: This isn't ideal. The request URI may be encoded (it's # non-normalized) slightly differently to the "real" SCRIPT_NAME # and PATH_INFO values. This causes problems when we compute path_info, # below. For now, don't use script names that will be subject to # encoding/decoding. self.path = force_unicode(req.uri) root = req.get_options().get('django.root', '') self.django_root = root # req.path_info isn't necessarily computed correctly in all # circumstances (it's out of mod_python's control a bit), so we use # req.uri and some string manipulations to get the right value. if root and req.uri.startswith(root): self.path_info = force_unicode(req.uri[len(root):]) else: self.path_info = self.path if not self.path_info: # Django prefers empty paths to be '/', rather than '', to give us # a common start character for URL patterns. So this is a little # naughty, but also pretty harmless. self.path_info = u'/' self._post_parse_error = False
def get_script_name(environ): """ Returns the equivalent of the HTTP request's SCRIPT_NAME environment variable. If Apache mod_rewrite has been used, returns what would have been the script name prior to any rewriting (so it's the script name as seen from the client's perspective), unless DJANGO_USE_POST_REWRITE is set (to anything). """ from google.appengine._internal.django.conf import settings if settings.FORCE_SCRIPT_NAME is not None: return force_unicode(settings.FORCE_SCRIPT_NAME) # If Apache's mod_rewrite had a whack at the URL, Apache set either # SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any # rewrites. Unfortunately not every Web server (lighttpd!) passes this # information through all the time, so FORCE_SCRIPT_NAME, above, is still # needed. script_url = environ.get('SCRIPT_URL', '') if not script_url: script_url = environ.get('REDIRECT_URL', '') if script_url: return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))]) return force_unicode(environ.get('SCRIPT_NAME', ''))
def save(self, name, content): """ Saves new content to the file specified by name. The content should be a proper File object, ready to be read from the beginning. """ # Get the proper name for the file, as it will actually be saved. if name is None: name = content.name name = self.get_available_name(name) name = self._save(name, content) # Store filenames with forward slashes, even on Windows return force_unicode(name.replace('\\', '/'))
def get_script_name(environ): """ Returns the equivalent of the HTTP request's SCRIPT_NAME environment variable. If Apache mod_rewrite has been used, returns what would have been the script name prior to any rewriting (so it's the script name as seen from the client's perspective), unless DJANGO_USE_POST_REWRITE is set (to anything). """ from google.appengine._internal.django.conf import settings if settings.FORCE_SCRIPT_NAME is not None: return force_unicode(settings.FORCE_SCRIPT_NAME) # If Apache's mod_rewrite had a whack at the URL, Apache set either # SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any # rewrites. Unfortunately not every Web server (lighttpd!) passes this # information through all the time, so FORCE_SCRIPT_NAME, above, is still # needed. script_url = environ.get('SCRIPT_URL', u'') if not script_url: script_url = environ.get('REDIRECT_URL', u'') if script_url: return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))]) return force_unicode(environ.get('SCRIPT_NAME', u''))
def __init__(self, req): self._req = req # FIXME: This isn't ideal. The request URI may be encoded (it's # non-normalized) slightly differently to the "real" SCRIPT_NAME # and PATH_INFO values. This causes problems when we compute path_info, # below. For now, don't use script names that will be subject to # encoding/decoding. self.path = force_unicode(req.uri) root = req.get_options().get('django.root', '') self.django_root = root # req.path_info isn't necessarily computed correctly in all # circumstances (it's out of mod_python's control a bit), so we use # req.uri and some string manipulations to get the right value. if root and req.uri.startswith(root): self.path_info = force_unicode(req.uri[len(root):]) else: self.path_info = self.path if not self.path_info: # Django prefers empty paths to be '/', rather than '', to give us # a common start character for URL patterns. So this is a little # naughty, but also pretty harmless. self.path_info = '/' self._post_parse_error = False
def reverse(self, lookup_view, *args, **kwargs): if args and kwargs: raise ValueError( "Don't mix *args and **kwargs in call to reverse()!") try: lookup_view = get_callable(lookup_view, True) except (ImportError, AttributeError) as e: raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e)) possibilities = self.reverse_dict.getlist(lookup_view) for possibility, pattern in possibilities: for result, params in possibility: if args: if len(args) != len(params): continue unicode_args = [force_unicode(val) for val in args] candidate = result % dict(list(zip(params, unicode_args))) else: if set(kwargs.keys()) != set(params): continue unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in list(kwargs.items())]) candidate = result % unicode_kwargs if re.search('^%s' % pattern, candidate, re.UNICODE): return candidate # lookup_view can be URL label, or dotted path, or callable, Any of # these can be passed in at the top, but callables are not friendly in # error messages. m = getattr(lookup_view, '__module__', None) n = getattr(lookup_view, '__name__', None) if m is not None and n is not None: lookup_view_s = "%s.%s" % (m, n) else: lookup_view_s = lookup_view raise NoReverseMatch( "Reverse for '%s' with arguments '%s' and keyword " "arguments '%s' not found." % (lookup_view_s, args, kwargs))
def truncate_words(s, num, end_text='...'): """Truncates a string after a certain number of words. Takes an optional argument of what should be used to notify that the string has been truncated, defaulting to ellipsis (...) Newlines in the string will be stripped. """ s = force_unicode(s) length = int(num) words = s.split() if len(words) > length: words = words[:length] if not words[-1].endswith(end_text): words.append(end_text) return ' '.join(words)
def render(self, context): try: output = self.filter_expression.resolve(context) output = localize(output) output = force_unicode(output) except TemplateSyntaxError as e: if not hasattr(e, 'source'): e.source = self.source raise except UnicodeDecodeError: return '' if (context.autoescape and not isinstance(output, SafeData)) or isinstance(output, EscapeData): return escape(output) else: return output
def render_node(self, node, context): try: result = node.render(context) except TemplateSyntaxError as e: if not hasattr(e, 'source'): e.source = node.source raise except Exception as e: from sys import exc_info wrapped = TemplateSyntaxError('Caught %s while rendering: %s' % (e.__class__.__name__, force_unicode(e, errors='replace'))) wrapped.source = node.source wrapped.exc_info = exc_info() raise wrapped.with_traceback(wrapped.exc_info[2]) return result
def sanitize_address(addr, encoding): if isinstance(addr, basestring): addr = parseaddr(force_unicode(addr)) nm, addr = addr nm = str(Header(nm, encoding)) try: addr = addr.encode('ascii') except UnicodeEncodeError: # IDN if u'@' in addr: localpart, domain = addr.split(u'@', 1) localpart = str(Header(localpart, encoding)) domain = domain.encode('idna') addr = '@'.join([localpart, domain]) else: addr = str(Header(addr, encoding)) return formataddr((nm, addr))
def sanitize_address(addr, encoding): if isinstance(addr, str): addr = parseaddr(force_unicode(addr)) nm, addr = addr nm = str(Header(nm, encoding)) try: addr = addr.encode('ascii') except UnicodeEncodeError: # IDN if '@' in addr: localpart, domain = addr.split('@', 1) localpart = str(Header(localpart, encoding)) domain = domain.encode('idna') addr = '@'.join([localpart, domain]) else: addr = str(Header(addr, encoding)) return formataddr((nm, addr))
class DebugNodeList(NodeList): def render_node(self, node, context): try: result = node.render(context) except TemplateSyntaxError, e: if not hasattr(e, 'source'): e.source = node.source raise except Exception, e: from sys import exc_info wrapped = TemplateSyntaxError( u'Caught %s while rendering: %s' % (e.__class__.__name__, force_unicode(e, errors='replace'))) wrapped.source = node.source wrapped.exc_info = exc_info() raise wrapped, None, wrapped.exc_info[2]
def smart_split(text): r""" Generator that splits a string by spaces, leaving quoted phrases together. Supports both single and double quotes, and supports escaping quotes with backslashes. In the output, strings will keep their initial and trailing quote marks and escaped quotes will remain escaped (the results can then be further processed with unescape_string_literal()). >>> list(smart_split(r'This is "a person\'s" test.')) [u'This', u'is', u'"a person\\\'s"', u'test.'] >>> list(smart_split(r"Another 'person\'s' test.")) [u'Another', u"'person\\'s'", u'test.'] >>> list(smart_split(r'A "\"funky\" style" test.')) [u'A', u'"\\"funky\\" style"', u'test.'] """ text = force_unicode(text) for bit in smart_split_re.finditer(text): yield bit.group(0)
def forbid_multi_line_headers(name, val, encoding): """Forbids multi-line headers, to prevent header injection.""" encoding = encoding or settings.DEFAULT_CHARSET val = force_unicode(val) if '\n' in val or '\r' in val: raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name)) try: val = val.encode('ascii') except UnicodeEncodeError: if name.lower() in ADDRESS_HEADERS: val = ', '.join(sanitize_address(addr, encoding) for addr in getaddresses((val,))) else: val = str(Header(val, encoding)) else: if name.lower() == 'subject': val = Header(val) return name, val