Home | History | Annotate | Download | only in webob
      1 # code stolen from "six"
      2 
      3 import sys
      4 import types
      5 
      6 # True if we are running on Python 3.
      7 PY3 = sys.version_info[0] == 3
      8 
      9 if PY3: # pragma: no cover
     10     string_types = str,
     11     integer_types = int,
     12     class_types = type,
     13     text_type = str
     14     long = int
     15 else:
     16     string_types = basestring,
     17     integer_types = (int, long)
     18     class_types = (type, types.ClassType)
     19     text_type = unicode
     20     long = long
     21 
     22 # TODO check if errors is ever used
     23 
     24 def text_(s, encoding='latin-1', errors='strict'):
     25     if isinstance(s, bytes):
     26         return s.decode(encoding, errors)
     27     return s
     28 
     29 def bytes_(s, encoding='latin-1', errors='strict'):
     30     if isinstance(s, text_type):
     31         return s.encode(encoding, errors)
     32     return s
     33 
     34 if PY3: # pragma: no cover
     35     def native_(s, encoding='latin-1', errors='strict'):
     36         if isinstance(s, text_type):
     37             return s
     38         return str(s, encoding, errors)
     39 else:
     40     def native_(s, encoding='latin-1', errors='strict'):
     41         if isinstance(s, text_type):
     42             return s.encode(encoding, errors)
     43         return str(s)
     44 
     45 try:
     46     from queue import Queue, Empty
     47 except ImportError:
     48     from Queue import Queue, Empty
     49 
     50 if PY3: # pragma: no cover
     51     from urllib import parse
     52     urlparse = parse
     53     from urllib.parse import quote as url_quote
     54     from urllib.parse import urlencode as url_encode, quote_plus
     55     from urllib.request import urlopen as url_open
     56 else:
     57     import urlparse
     58     from urllib import quote_plus
     59     from urllib import quote as url_quote
     60     from urllib import unquote as url_unquote
     61     from urllib import urlencode as url_encode
     62     from urllib2 import urlopen as url_open
     63 
     64 if PY3: # pragma: no cover
     65     def reraise(exc_info):
     66         etype, exc, tb = exc_info
     67         if exc.__traceback__ is not tb:
     68             raise exc.with_traceback(tb)
     69         raise exc
     70 else: # pragma: no cover
     71     exec("def reraise(exc): raise exc[0], exc[1], exc[2]")
     72 
     73 
     74 if PY3: # pragma: no cover
     75     def iteritems_(d):
     76         return d.items()
     77     def itervalues_(d):
     78         return d.values()
     79 else:
     80     def iteritems_(d):
     81         return d.iteritems()
     82     def itervalues_(d):
     83         return d.itervalues()
     84 
     85 
     86 if PY3: # pragma: no cover
     87     def unquote(string):
     88         if not string:
     89             return b''
     90         res = string.split(b'%')
     91         if len(res) != 1:
     92             string = res[0]
     93             for item in res[1:]:
     94                 try:
     95                     string += bytes([int(item[:2], 16)]) + item[2:]
     96                 except ValueError:
     97                     string += b'%' + item
     98         return string
     99 
    100     def url_unquote(s):
    101         return unquote(s.encode('ascii')).decode('latin-1')
    102 
    103     def parse_qsl_text(qs, encoding='utf-8'):
    104         qs = qs.encode('latin-1')
    105         qs = qs.replace(b'+', b' ')
    106         pairs = [s2 for s1 in qs.split(b'&') for s2 in s1.split(b';') if s2]
    107         for name_value in pairs:
    108             nv = name_value.split(b'=', 1)
    109             if len(nv) != 2:
    110                 nv.append('')
    111             name = unquote(nv[0])
    112             value = unquote(nv[1])
    113             yield (name.decode(encoding), value.decode(encoding))
    114 
    115 else:
    116     from urlparse import parse_qsl
    117 
    118     def parse_qsl_text(qs, encoding='utf-8'):
    119         qsl = parse_qsl(
    120             qs,
    121             keep_blank_values=True,
    122             strict_parsing=False
    123         )
    124         for (x, y) in qsl:
    125             yield (x.decode(encoding), y.decode(encoding))
    126 
    127 
    128 if PY3: # pragma no cover
    129     from html import escape
    130 else:
    131     from cgi import escape
    132 
    133 
    134 # We only need this on Python3 but the issue was fixed in Pytohn 3.4.4 and 3.5.
    135 if PY3 and sys.version_info[:3] < (3, 4, 4):  # pragma no cover
    136     # Work around http://bugs.python.org/issue23801
    137     import cgi
    138     from cgi import FieldStorage as _cgi_FieldStorage
    139 
    140     class cgi_FieldStorage(_cgi_FieldStorage):
    141         # This is taken exactly from Python 3.5's cgi.py module, and patched
    142         # with the patch from http://bugs.python.org/issue23801.
    143         def read_multi(self, environ, keep_blank_values, strict_parsing):
    144             """Internal: read a part that is itself multipart."""
    145             ib = self.innerboundary
    146             if not cgi.valid_boundary(ib):
    147                 raise ValueError(
    148                     'Invalid boundary in multipart form: %r' % (ib,))
    149             self.list = []
    150             if self.qs_on_post:
    151                 query = cgi.urllib.parse.parse_qsl(
    152                     self.qs_on_post, self.keep_blank_values,
    153                     self.strict_parsing,
    154                     encoding=self.encoding, errors=self.errors)
    155                 for key, value in query:
    156                     self.list.append(cgi.MiniFieldStorage(key, value))
    157 
    158             klass = self.FieldStorageClass or self.__class__
    159             first_line = self.fp.readline()  # bytes
    160             if not isinstance(first_line, bytes):
    161                 raise ValueError("%s should return bytes, got %s"
    162                                  % (self.fp, type(first_line).__name__))
    163             self.bytes_read += len(first_line)
    164 
    165             # Ensure that we consume the file until we've hit our innerboundary
    166             while (first_line.strip() != (b"--" + self.innerboundary) and
    167                     first_line):
    168                 first_line = self.fp.readline()
    169                 self.bytes_read += len(first_line)
    170 
    171             while True:
    172                 parser = cgi.FeedParser()
    173                 hdr_text = b""
    174                 while True:
    175                     data = self.fp.readline()
    176                     hdr_text += data
    177                     if not data.strip():
    178                         break
    179                 if not hdr_text:
    180                     break
    181                 # parser takes strings, not bytes
    182                 self.bytes_read += len(hdr_text)
    183                 parser.feed(hdr_text.decode(self.encoding, self.errors))
    184                 headers = parser.close()
    185                 part = klass(self.fp, headers, ib, environ, keep_blank_values,
    186                              strict_parsing, self.limit-self.bytes_read,
    187                              self.encoding, self.errors)
    188                 self.bytes_read += part.bytes_read
    189                 self.list.append(part)
    190                 if part.done or self.bytes_read >= self.length > 0:
    191                     break
    192             self.skip_lines()
    193 else:
    194     from cgi import FieldStorage as cgi_FieldStorage
    195