thirdparty/google_appengine/lib/webob/tests/test_request.txt
author Sverre Rabbelier <srabbelier@gmail.com>
Tue, 02 Dec 2008 17:59:44 +0000
changeset 647 355ac73823a1
parent 109 620f9b141567
permissions -rw-r--r--
Swap order of merged params to fix sponsor select view The sponsor select view (in 'create new program') was showing the wrong information (and also using the wrong list template) because the order in which the params were merged was wrong way around. This fixes that and at the same time fixes the 'instruction_text' attribute, which should be named 'list_description' instead. At the same time we lookup and set Sponsor as the scope of the newly created program. Patch by: Sverre Rabbelier

This demonstrates how the Request object works, and tests it.

You can instantiate a request using ``Request.blank()``, to create a
fresh environment dictionary with all the basic keys such a dictionary
should have.

    >>> from dtopt import ELLIPSIS
    >>> from webob import Request, UTC
    >>> req = Request.blank('/')
    >>> req # doctest: +ELLIPSIS
    <Request at ... GET http://localhost/>
    >>> print repr(str(req))
    'GET /\r\nHost: localhost:80\r\n\r\n'
    >>> req.environ # doctest: +ELLIPSIS
    {...}
    >>> req.body_file # doctest: +ELLIPSIS
    <cStringIO.StringI object at ...>
    >>> req.scheme
    'http'
    >>> req.method
    'GET'
    >>> req.script_name
    ''
    >>> req.path_info
    '/'
    >>> req.content_type
    ''
    >>> print req.remote_user
    None
    >>> req.host_url
    'http://localhost'
    >>> req.script_name = '/foo'
    >>> req.path_info = '/bar/'
    >>> req.environ['QUERY_STRING'] = 'a=b'
    >>> req.application_url
    'http://localhost/foo'
    >>> req.path_url
    'http://localhost/foo/bar/'
    >>> req.url
    'http://localhost/foo/bar/?a=b'
    >>> req.relative_url('baz')
    'http://localhost/foo/bar/baz'
    >>> req.relative_url('baz', to_application=True)
    'http://localhost/foo/baz'
    >>> req.relative_url('http://example.org')
    'http://example.org'
    >>> req.path_info_peek()
    'bar'
    >>> req.path_info_pop()
    'bar'
    >>> req.script_name, req.path_info
    ('/foo/bar', '/')
    >>> print req.environ.get('wsgiorg.routing_args')
    None
    >>> req.urlvars
    {}
    >>> req.environ['wsgiorg.routing_args']
    ((), {})
    >>> req.urlvars = dict(x='y')
    >>> req.environ['wsgiorg.routing_args']
    ((), {'x': 'y'})
    >>> req.urlargs
    ()
    >>> req.urlargs = (1, 2, 3)
    >>> req.environ['wsgiorg.routing_args']
    ((1, 2, 3), {'x': 'y'})
    >>> del req.urlvars
    >>> req.environ['wsgiorg.routing_args']
    ((1, 2, 3), {})
    >>> req.urlvars = {'test': 'value'}
    >>> del req.urlargs
    >>> req.environ['wsgiorg.routing_args']
    ((), {'test': 'value'})
    >>> req.is_xhr
    False
    >>> req.environ['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
    >>> req.is_xhr
    True
    >>> req.host
    'localhost:80'

There are also variables to access the variables and body:

    >>> from cStringIO import StringIO
    >>> body = 'var1=value1&var2=value2&rep=1&rep=2'
    >>> req = Request.blank('/')
    >>> req.method = 'POST'
    >>> req.body_file = StringIO(body)
    >>> req.environ['CONTENT_LENGTH'] = str(len(body))
    >>> vars = req.str_POST
    >>> vars
    MultiDict([('var1', 'value1'), ('var2', 'value2'), ('rep', '1'), ('rep', '2')])
    >>> vars is req.str_POST
    True
    >>> req.POST
    MultiDict([('var1', 'value1'), ('var2', 'value2'), ('rep', '1'), ('rep', '2')])
    >>> req.charset = 'utf8'
    >>> req.POST
    UnicodeMultiDict([(u'var1', u'value1'), (u'var2', u'value2'), (u'rep', u'1'), (u'rep', u'2')])

Note that the variables are there for GET requests and non-form POST
requests, but they are empty and read-only:

    >>> req = Request.blank('/')
    >>> req.str_POST
    <NoVars: Not a POST request>
    >>> req.str_POST.items()
    []
    >>> req.str_POST['x'] = 'y'
    Traceback (most recent call last):
        ...
    KeyError: 'Cannot add variables: Not a POST request'
    >>> req.method = 'POST'
    >>> req.str_POST
    MultiDict([])
    >>> req.content_type = 'text/xml'
    >>> req.body_file = StringIO('<xml></xml>')
    >>> req.str_POST
    <NoVars: Not an HTML form submission (Content-Type: text/xml)>
    >>> req.body
    '<xml></xml>'

You can also get access to the query string variables, of course:

    >>> req = Request.blank('/?a=b&d=e&d=f')
    >>> req.GET
    MultiDict([('a', 'b'), ('d', 'e'), ('d', 'f')])
    >>> req.GET['d']
    'f'
    >>> req.GET.getall('d')
    ['e', 'f']
    >>> req.method = 'POST'
    >>> req.body = 'x=y&d=g'
    >>> req.body_file # doctest: +ELLIPSIS
    <cStringIO.StringI object at ...>
    >>> req.environ['CONTENT_LENGTH']
    '7'
    >>> req.params
    NestedMultiDict([('a', 'b'), ('d', 'e'), ('d', 'f'), ('x', 'y'), ('d', 'g')])
    >>> req.params['d']
    'f'
    >>> req.params.getall('d')
    ['e', 'f', 'g']

Cookie are viewed as a dictionary (*view only*):

    >>> req = Request.blank('/')
    >>> req.environ['HTTP_COOKIE'] = 'var1=value1; var2=value2'
    >>> req.str_cookies
    {'var1': 'value1', 'var2': 'value2'}
    >>> req.cookies
    {'var1': 'value1', 'var2': 'value2'}
    >>> req.charset = 'utf8'
    >>> req.cookies
    UnicodeMultiDict([(u'var1', u'value1'), (u'var2', u'value2')])

Sometimes conditional headers are problematic.  You can remove them:

    >>> from datetime import datetime
    >>> req = Request.blank('/')
    >>> req.if_match = 'some-etag'
    >>> req.if_modified_since = datetime(2005, 1, 1, 12, 0)
    >>> req.environ['HTTP_ACCEPT_ENCODING'] = 'gzip'
    >>> print req.headers
    {'Host': 'localhost:80', 'If-Match': 'some-etag', 'Accept-Encoding': 'gzip', 'If-Modified-Since': 'Sat, 01 Jan 2005 12:00:00 GMT'}
    >>> req.remove_conditional_headers()
    >>> print req.headers
    {'Host': 'localhost:80'}

Some headers are handled specifically (more should be added):

    >>> req = Request.blank('/')
    >>> req.if_none_match = 'xxx'
    >>> 'xxx' in req.if_none_match
    True
    >>> 'yyy' in req.if_none_match
    False
    >>> req.if_modified_since = datetime(2005, 1, 1, 12, 0)
    >>> req.if_modified_since < datetime(2006, 1, 1, 12, 0, tzinfo=UTC)
    True
    >>> req.user_agent
    ''
    >>> req.user_agent = 'MSIE-Win'
    >>> req.user_agent
    'MSIE-Win'

Accept-* headers are parsed into read-only objects that support
containment tests, and some useful methods.  Note that parameters on
mime types are not supported.

    >>> req = Request.blank('/')
    >>> req.environ['HTTP_ACCEPT'] = "text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5"
    >>> req.accept # doctest: +ELLIPSIS
    <MIMEAccept at ... Accept: text/*;q=0.3, text/html;q=0.7, text/html, text/html;q=0.4, */*;q=0.5>
    >>> for item, quality in req.accept._parsed:
    ...     print '%s: %0.1f' % (item, quality)
    text/*: 0.3
    text/html: 0.7
    text/html: 1.0
    text/html: 0.4
    */*: 0.5
    >>> '%0.1f' % req.accept.quality('text/html')
    '0.3'
    >>> req.accept.first_match(['text/plain', 'text/html', 'image/png'])
    'text/plain'
    >>> 'image/png' in req.accept
    True
    >>> req.environ['HTTP_ACCEPT'] = "text/html, application/xml; q=0.7, text/*; q=0.5, */*; q=0.1"
    >>> req.accept # doctest: +ELLIPSIS
    <MIMEAccept at ... Accept: text/html, application/xml;q=0.7, text/*;q=0.5, */*;q=0.1>
    >>> req.accept.best_match(['text/plain', 'application/xml'])
    'application/xml'
    >>> req.accept.first_match(['application/xml', 'text/html'])
    'application/xml'
    >>> req.accept = "text/html, application/xml, text/*; q=0.5"
    >>> 'image/png' in req.accept
    False
    >>> 'text/plain' in req.accept
    True
    >>> req.accept_charset = 'utf8'
    >>> 'UTF8' in req.accept_charset
    True
    >>> 'gzip' in req.accept_encoding
    False
    >>> req.accept_encoding = 'gzip'
    >>> 'GZIP' in req.accept_encoding
    True
    >>> req.accept_language = {'en-US': 0.5, 'es': 0.7}
    >>> str(req.accept_language)
    'es;q=0.7, en-US;q=0.5'
    >>> req.headers['Accept-Language']
    'es;q=0.7, en-US;q=0.5'
    >>> req.accept_language.best_matches('en-GB')
    ['es', 'en-US', 'en-GB']
    >>> req.accept_language.best_matches('es')
    ['es']
    >>> req.accept_language.best_matches('ES')
    ['es']

The If-Range header is a combination of a possible conditional date or
etag match::

    >>> req = Request.blank('/')
    >>> req.if_range = 'asdf'
    >>> req.if_range
    <IfRange etag=asdf, date=*>
    >>> from webob import Response
    >>> res = Response()
    >>> res.etag = 'asdf'
    >>> req.if_range.match_response(res)
    True
    >>> res.etag = None
    >>> req.if_range.match_response(res)
    False
    >>> res.last_modified = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
    >>> req.if_range = datetime(2006, 1, 1, 12, 0, tzinfo=UTC)
    >>> req.if_range
    <IfRange etag=*, date=Sun, 01 Jan 2006 12:00:00 GMT>
    >>> req.if_range.match_response(res)
    True
    >>> res.last_modified = datetime(2007, 1, 1, 12, 0, tzinfo=UTC)
    >>> req.if_range.match_response(res)
    False
    >>> req = Request.blank('/')
    >>> req.if_range
    <Empty If-Range>
    >>> req.if_range.match_response(res)
    True

Ranges work like so::

    >>> req = Request.blank('/')
    >>> req.range = (0, 100)
    >>> req.range
    <Range ranges=(0, 100)>
    >>> str(req.range)
    'bytes=0-101'

You can use them with responses::

    >>> res = Response()
    >>> res.content_range = req.range.content_range(1000)
    >>> res.content_range
    <ContentRange bytes 0-101/1000>
    >>> str(res.content_range)
    'bytes 0-101/1000'
    >>> start, end, length = res.content_range
    >>> start, end, length
    (0, 100, 1000)

A quick test of caching the request body:

    >>> from cStringIO import StringIO
    >>> length = Request.request_body_tempfile_limit+10
    >>> data = StringIO('x'*length)
    >>> req = Request.blank('/')
    >>> req.content_length = length
    >>> req.body_file = data
    >>> req.body_file
    <cStringIO.StringI object at ...>
    >>> len(req.body)
    10250
    >>> req.body_file
    <open file '<fdopen>', mode 'w+b' at ...>

Some query tests:

    >>> req = Request.blank('/')
    >>> req.GET.get('unknown')
    >>> req.GET.get('unknown', '?')
    '?'
    >>> req.POST.get('unknown')
    >>> req.POST.get('unknown', '?')
    '?'
    >>> req.params.get('unknown')
    >>> req.params.get('unknown', '?')
    '?'