]> git.donarmstrong.com Git - neurodebian.git/blob - sphinx/sphinxext/feed/django_support.py
Merge branch 'master' into newdesign
[neurodebian.git] / sphinx / sphinxext / feed / django_support.py
1 """
2 utils needed for django's feed generator
3 """
4
5 """
6 Utilities for XML generation/parsing.
7 from django.utils.xmlutils import SimplerXMLGenerator
8 """
9
10 from xml.sax.saxutils import XMLGenerator
11
12 class SimplerXMLGenerator(XMLGenerator):
13     def addQuickElement(self, name, contents=None, attrs=None):
14         "Convenience method for adding an element with no children"
15         if attrs is None: attrs = {}
16         self.startElement(name, attrs)
17         if contents is not None:
18             self.characters(contents)
19         self.endElement(name)
20         
21 """
22 from django.utils.encoding import force_unicode, iri_to_uri
23 """
24 import types
25 import urllib
26 import locale
27 import datetime
28 import codecs
29 from decimal import Decimal
30
31 class DjangoUnicodeDecodeError(UnicodeDecodeError):
32     def __init__(self, obj, *args):
33         self.obj = obj
34         UnicodeDecodeError.__init__(self, *args)
35
36     def __str__(self):
37         original = UnicodeDecodeError.__str__(self)
38         return '%s. You passed in %r (%s)' % (original, self.obj,
39                 type(self.obj))
40
41 class StrAndUnicode(object):
42     """
43     A class whose __str__ returns its __unicode__ as a UTF-8 bytestring.
44
45     Useful as a mix-in.
46     """
47     def __str__(self):
48         return self.__unicode__().encode('utf-8')
49
50 def is_protected_type(obj):
51     """Determine if the object instance is of a protected type.
52
53     Objects of protected types are preserved as-is when passed to
54     force_unicode(strings_only=True).
55     """
56     return isinstance(obj, (
57         types.NoneType,
58         int, long,
59         datetime.datetime, datetime.date, datetime.time,
60         float, Decimal)
61     )
62
63 def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
64     """
65     Similar to smart_unicode, except that lazy instances are resolved to
66     strings, rather than kept as lazy objects.
67
68     If strings_only is True, don't convert (some) non-string-like objects.
69     """
70     if strings_only and is_protected_type(s):
71         return s
72     try:
73         if not isinstance(s, basestring,):
74             if hasattr(s, '__unicode__'):
75                 s = unicode(s)
76             else:
77                 try:
78                     s = unicode(str(s), encoding, errors)
79                 except UnicodeEncodeError:
80                     if not isinstance(s, Exception):
81                         raise
82                     # If we get to here, the caller has passed in an Exception
83                     # subclass populated with non-ASCII data without special
84                     # handling to display as a string. We need to handle this
85                     # without raising a further exception. We do an
86                     # approximation to what the Exception's standard str()
87                     # output should be.
88                     s = ' '.join([force_unicode(arg, encoding, strings_only,
89                             errors) for arg in s])
90         elif not isinstance(s, unicode):
91             # Note: We use .decode() here, instead of unicode(s, encoding,
92             # errors), so that if s is a SafeString, it ends up being a
93             # SafeUnicode at the end.
94             s = s.decode(encoding, errors)
95     except UnicodeDecodeError, e:
96         if not isinstance(s, Exception):
97             raise DjangoUnicodeDecodeError(s, *e.args)
98         else:
99             # If we get to here, the caller has passed in an Exception
100             # subclass populated with non-ASCII bytestring data without a
101             # working unicode method. Try to handle this without raising a
102             # further exception by individually forcing the exception args
103             # to unicode.
104             s = ' '.join([force_unicode(arg, encoding, strings_only,
105                     errors) for arg in s])
106     return s
107
108 def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'):
109     """
110     Returns a bytestring version of 's', encoded as specified in 'encoding'.
111
112     If strings_only is True, don't convert (some) non-string-like objects.
113     """
114     if strings_only and isinstance(s, (types.NoneType, int)):
115         return s
116     elif not isinstance(s, basestring):
117         try:
118             return str(s)
119         except UnicodeEncodeError:
120             if isinstance(s, Exception):
121                 # An Exception subclass containing non-ASCII data that doesn't
122                 # know how to print itself properly. We shouldn't raise a
123                 # further exception.
124                 return ' '.join([smart_str(arg, encoding, strings_only,
125                         errors) for arg in s])
126             return unicode(s).encode(encoding, errors)
127     elif isinstance(s, unicode):
128         return s.encode(encoding, errors)
129     elif s and encoding != 'utf-8':
130         return s.decode('utf-8', errors).encode(encoding, errors)
131     else:
132         return s
133
134 def iri_to_uri(iri):
135     """
136     Convert an Internationalized Resource Identifier (IRI) portion to a URI
137     portion that is suitable for inclusion in a URL.
138
139     This is the algorithm from section 3.1 of RFC 3987.  However, since we are
140     assuming input is either UTF-8 or unicode already, we can simplify things a
141     little from the full method.
142
143     Returns an ASCII string containing the encoded result.
144     """
145     # The list of safe characters here is constructed from the "reserved" and
146     # "unreserved" characters specified in sections 2.2 and 2.3 of RFC 3986:
147     #     reserved    = gen-delims / sub-delims
148     #     gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
149     #     sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
150     #                   / "*" / "+" / "," / ";" / "="
151     #     unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
152     # Of the unreserved characters, urllib.quote already considers all but
153     # the ~ safe.
154     # The % character is also added to the list of safe characters here, as the
155     # end of section 3.1 of RFC 3987 specifically mentions that % must not be
156     # converted.
157     if iri is None:
158         return iri
159     return urllib.quote(smart_str(iri), safe="/#%[]=:;$&()+,!?*@'~")
160
161
162 # The encoding of the default system locale but falls back to the
163 # given fallback encoding if the encoding is unsupported by python or could
164 # not be determined.  See tickets #10335 and #5846
165 try:
166     DEFAULT_LOCALE_ENCODING = locale.getdefaultlocale()[1] or 'ascii'
167     codecs.lookup(DEFAULT_LOCALE_ENCODING)
168 except:
169     DEFAULT_LOCALE_ENCODING = 'ascii'
170