changeset 4689:bd3f5ccf6fb6

updated werkzeug
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sun, 19 Apr 2009 00:46:15 +0200
parents 3e4e67bcbedd
children 61322779dd5d
files MoinMoin/support/werkzeug/datastructures.py MoinMoin/support/werkzeug/test.py MoinMoin/support/werkzeug/useragents.py MoinMoin/support/werkzeug/utils.py
diffstat 4 files changed, 110 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/support/werkzeug/datastructures.py	Sun Apr 19 00:38:06 2009 +0200
+++ b/MoinMoin/support/werkzeug/datastructures.py	Sun Apr 19 00:46:15 2009 +0200
@@ -238,11 +238,6 @@
                     or `None`.
     """
 
-    # internal list type.  This is an internal interface!  do not use.
-    # it's only used in methods that do not modify the multi dict so that
-    # ImmutableMultiDict can use it without much hassle.
-    _list_type = list
-
     # the key error this class raises.  Because of circular dependencies
     # with the http exception module this class is created at the end of
     # this module.
@@ -250,23 +245,21 @@
 
     def __init__(self, mapping=None):
         if isinstance(mapping, MultiDict):
-            dict.__init__(self, ((k, self._list_type(v))
-                          for k, v in mapping.lists()))
+            dict.__init__(self, ((k, l[:]) for k, l in mapping.lists()))
         elif isinstance(mapping, dict):
             tmp = {}
             for key, value in mapping.iteritems():
                 if isinstance(value, (tuple, list)):
-                    value = self._list_type(value)
+                    value = list(value)
                 else:
-                    value = self._list_type([value])
+                    value = [value]
                 tmp[key] = value
             dict.__init__(self, tmp)
         else:
             tmp = {}
             for key, value in mapping or ():
                 tmp.setdefault(key, []).append(value)
-            dict.__init__(self, (dict((k, self._list_type(v))
-                                 for k, v in tmp.iteritems())))
+            dict.__init__(self, tmp)
 
     def __getitem__(self, key):
         """Return the first data value for this key;
@@ -298,16 +291,16 @@
         try:
             rv = dict.__getitem__(self, key)
         except KeyError:
-            return self._list_type()
+            return []
         if type is None:
-            return rv
+            return list(rv)
         result = []
         for item in rv:
             try:
                 result.append(type(item))
             except ValueError:
                 pass
-        return self._list_type(result)
+        return result
 
     def setlist(self, key, new_list):
         """Remove the old values for a key and add new ones.  Note that the list
@@ -341,8 +334,16 @@
             default = self[key]
         return default
 
-    def setlistdefault(self, key, default_list=()):
-        """Like `setdefault` but sets multiple values.
+    def setlistdefault(self, key, default_list=None):
+        """Like `setdefault` but sets multiple values.  The list returned
+        is not a copy, but the list that is actually used internally.  This
+        means that you can put new values into the dict by appending items
+        to the list:
+
+        >>> d = MultiDict({"foo": 1})
+        >>> d.setlistdefault("foo").extend([2, 3])
+        >>> d.getlist("foo")
+        [1, 2, 3]
 
         :param key: The key to be looked up.
         :param default: An iterable of default values.  It is either copied
@@ -351,10 +352,10 @@
         :return: a :class:`list`
         """
         if key not in self:
-            default_list = list(default_list)
+            default_list = list(default_list or ())
             dict.__setitem__(self, key, default_list)
         else:
-            default_list = self.getlist(key)
+            default_list = dict.__getitem__(self, key)
         return default_list
 
     def items(self):
@@ -378,33 +379,40 @@
         """
         return [self[key] for key in self.iterkeys()]
 
-    #: Return a list of all values associated with a key.  Zipping
-    #: :meth:`keys` and this is the same as calling :meth:`lists`:
-    #:
-    #: >>> d = MultiDict({"foo": [1, 2, 3]})
-    #: >>> zip(d.keys(), d.listvalues()) == d.lists()
-    #: True
-    #:
-    #: :return: a :class:`list`
-    listvalues = dict.values
+    def listvalues(self):
+        """Return a list of all values associated with a key.  Zipping
+        :meth:`keys` and this is the same as calling :meth:`lists`:
+
+        >>> d = MultiDict({"foo": [1, 2, 3]})
+        >>> zip(d.keys(), d.listvalues()) == d.lists()
+        True
+        
+        :return: a :class:`list`
+        """
+        return list(self.iterlistvalues())
 
     def iteritems(self):
         """Like :meth:`items` but returns an iterator."""
         for key, values in dict.iteritems(self):
             yield key, values[0]
 
-    #: Return a list of all values associated with a key.
-    #:
-    #: :return: a :class:`list`
-    iterlists = dict.iteritems
+    def iterlists(self):
+        """Return a list of all values associated with a key.
+
+        :return: a class:`list`
+        """
+        for key, values in dict.iteritems(self):
+            yield key, list(values)
 
     def itervalues(self):
         """Like :meth:`values` but returns an iterator."""
         for values in dict.itervalues(self):
             yield values[0]
 
-    #: like :meth:`listvalues` but returns an iterator.
-    iterlistvalues = dict.itervalues
+    def iterlistvalues(self):
+        """like :meth:`listvalues` but returns an iterator."""
+        for values in dict.itervalues(self):
+            yield list(values)
 
     def copy(self):
         """Return a shallow copy of this object."""
@@ -932,8 +940,6 @@
     exceptions.
     """
 
-    _list_type = ImmutableList
-
     def __init__(self, dicts=None):
         self.dicts = dicts or []
 
@@ -963,7 +969,7 @@
         rv = []
         for d in self.dicts:
             rv.extend(d.getlist(key, type))
-        return self._list_type(rv)
+        return rv
 
     def keys(self):
         rv = set()
@@ -994,8 +1000,7 @@
         for d in self.dicts:
             for key, values in d.iterlists():
                 rv.setdefault(key, []).extend(values)
-        for key, values in rv.iteritems():
-            yield key, ImmutableList(values)
+        return rv.iteritems()
 
     def lists(self):
         return list(self.iterlists())
@@ -1086,14 +1091,11 @@
 
 
 class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict):
-    """An immutable :class:`MultiDict`.  The methods that return the internal
-    lists return :class:`ImmutableList` objects.
+    """An immutable :class:`MultiDict`.
 
     .. versionadded:: 0.5
     """
 
-    _list_type = ImmutableList
-
 
 class Accept(ImmutableList):
     """An :class:`Accept` object is just a list subclass for lists of
--- a/MoinMoin/support/werkzeug/test.py	Sun Apr 19 00:38:06 2009 +0200
+++ b/MoinMoin/support/werkzeug/test.py	Sun Apr 19 00:46:15 2009 +0200
@@ -22,7 +22,7 @@
 from werkzeug._internal import _empty_stream
 from werkzeug.wrappers import BaseRequest
 from werkzeug.utils import create_environ, run_wsgi_app, get_current_url, \
-     url_encode, url_decode, FileStorage
+     url_encode, url_decode, FileStorage, get_host
 from werkzeug.datastructures import FileMultiDict, MultiDict, \
      CombinedMultiDict, Headers
 
@@ -628,16 +628,33 @@
         if self.cookie_jar is not None:
             self.cookie_jar.extract_wsgi(environ, rv[2])
 
-        if rv[0].status_code in (301, 302, 303, 305, 307) and follow_redirects:
-            redirect = urlparse.urlunsplit(urlparse.urlsplit(
-                dict(rv[2])['Location'])[:-2] + ('', ''))
+        # handle redirects
+        redirect_chain = []
+        status_code = int(rv[1].split(None, 1)[0])
+        while status_code in (301, 302, 303, 305, 307) and follow_redirects:
+            redirect = dict(rv[2])['Location']
+            host = get_host(create_environ('/', redirect))
+            if get_host(environ).split(':', 1)[0] != host:
+                raise RuntimeError('%r does not support redirect to '
+                                   'external targets' % self.__class__)
+
+            scheme, netloc, script_root, qs, anchor = urlparse.urlsplit(redirect)
+            redirect_chain.append((redirect, status_code))
+
             kwargs.update({
-                'base_url':         redirect,
+                'base_url':         urlparse.urlunsplit((scheme, host,
+                                    script_root, '', '')).rstrip('/') + '/',
+                'query_string':     qs,
                 'as_tuple':         as_tuple,
                 'buffered':         buffered,
-                'follow_redirects': True
+                'follow_redirects': False
             })
-            return self.open(*args, **kwargs)
+            rv = self.open(*args, **kwargs)
+            status_code = int(rv[1].split(None, 1)[0])
+
+            # Prevent loops
+            if redirect_chain[-1] in redirect_chain[0:-1]:
+                break
 
         response = self.response_wrapper(*rv)
         if as_tuple:
--- a/MoinMoin/support/werkzeug/useragents.py	Sun Apr 19 00:38:06 2009 +0200
+++ b/MoinMoin/support/werkzeug/useragents.py	Sun Apr 19 00:46:15 2009 +0200
@@ -98,11 +98,49 @@
 
     .. attribute:: platform
 
-       the browser platform
+       the browser platform.  The following platforms are currently
+       recognized:
+
+       -   `aix`
+       -   `amiga`
+       -   `android`
+       -   `bsd`
+       -   `hpux`
+       -   `iphone`
+       -   `irix`
+       -   `linux`
+       -   `macos`
+       -   `sco`
+       -   `solaris`
+       -   `wii`
+       -   `windows`
 
     .. attribute:: browser
 
-        the name of the browser
+        the name of the browser.  The following browsers are currently
+        recognized:
+
+        -   `aol` *
+        -   `ask` *
+        -   `camino`
+        -   `chrome`
+        -   `firefox`
+        -   `galeon`
+        -   `google` *
+        -   `kmeleon`
+        -   `konqueror`
+        -   `links`
+        -   `lynx`
+        -   `msie`
+        -   `msn`
+        -   `netscape`
+        -   `opera`
+        -   `safari`
+        -   `seamonkey`
+        -   `webkit`
+        -   `yahoo` *
+
+        (Browsers maked with a star (``*``) are crawlers.)
 
     .. attribute:: version
 
--- a/MoinMoin/support/werkzeug/utils.py	Sun Apr 19 00:38:06 2009 +0200
+++ b/MoinMoin/support/werkzeug/utils.py	Sun Apr 19 00:46:15 2009 +0200
@@ -1109,7 +1109,7 @@
 
 
 def secure_filename(filename):
-    """Pass it a filename and it will return a secure version of it.  This
+    r"""Pass it a filename and it will return a secure version of it.  This
     filename can then savely be stored on a regular file system and passed
     to :func:`os.path.join`.  The filename returned is an ASCII only string
     for maximum portability.
@@ -1510,9 +1510,7 @@
         if ':' in import_name:
             module, obj = import_name.split(':', 1)
         elif '.' in import_name:
-            items = import_name.split('.')
-            module = '.'.join(items[:-1])
-            obj = items[-1]
+            module, obj = import_name.rsplit('.', 1)
         else:
             return __import__(import_name)
         return getattr(__import__(module, None, None, [obj]), obj)