thirdparty/google_appengine/lib/webob/tests/test_response.txt
changeset 109 620f9b141567
equal deleted inserted replaced
108:261778de26ff 109:620f9b141567
       
     1 This demonstrates how the Response object works, and tests it at the
       
     2 same time.
       
     3 
       
     4     >>> from dtopt import ELLIPSIS
       
     5     >>> from webob import Response, UTC
       
     6     >>> from datetime import datetime
       
     7     >>> res = Response('Test', status='200 OK')
       
     8 
       
     9 This is a minimal response object.  We can do things like get and set
       
    10 the body:
       
    11 
       
    12     >>> res.body
       
    13     'Test'
       
    14     >>> res.body = 'Another test'
       
    15     >>> res.body
       
    16     'Another test'
       
    17     >>> res.body = 'Another'
       
    18     >>> res.write(' test')
       
    19     >>> res.app_iter
       
    20     ['Another test']
       
    21     >>> res.content_length
       
    22     12
       
    23     >>> res.headers['content-length']
       
    24     '12'
       
    25     
       
    26 Content-Length is only applied when setting the body to a string; you
       
    27 have to set it manually otherwise.  There are also getters and setters
       
    28 for the various pieces:
       
    29 
       
    30     >>> res.app_iter = ['test']
       
    31     >>> print res.content_length
       
    32     None
       
    33     >>> res.content_length = 4
       
    34     >>> res.status
       
    35     '200 OK'
       
    36     >>> res.status_int
       
    37     200
       
    38     >>> res.headers
       
    39     HeaderDict([('content-type', 'text/html; charset=utf8'), ('Content-Length', '4')])
       
    40     >>> res.headerlist
       
    41     [('content-type', 'text/html; charset=utf8'), ('Content-Length', '4')]
       
    42 
       
    43 Content-type and charset are handled separately as properties, though
       
    44 they are both in the ``res.headers['content-type']`` header:
       
    45 
       
    46     >>> res.content_type
       
    47     'text/html'
       
    48     >>> res.content_type = 'text/html'
       
    49     >>> res.content_type
       
    50     'text/html'
       
    51     >>> res.charset
       
    52     'utf8'
       
    53     >>> res.charset = 'iso-8859-1'
       
    54     >>> res.charset
       
    55     'iso-8859-1'
       
    56     >>> res.content_type
       
    57     'text/html'
       
    58     >>> res.headers['content-type']
       
    59     'text/html; charset=iso-8859-1'
       
    60 
       
    61 Cookie handling is done through methods:
       
    62 
       
    63     >>> res.set_cookie('test', 'value')
       
    64     >>> res.headers['set-cookie']
       
    65     'test=value; Path=/'
       
    66     >>> res.set_cookie('test2', 'value2', max_age=10000)
       
    67     >>> res.headers['set-cookie'] # We only see the last header
       
    68     'test2=value2; Max-Age=10000; Path=/'
       
    69     >>> res.headers.getall('set-cookie')
       
    70     ['test=value; Path=/', 'test2=value2; Max-Age=10000; Path=/']
       
    71     >>> res.unset_cookie('test')
       
    72     >>> res.headers.getall('set-cookie')
       
    73     ['test2=value2; Max-Age=10000; Path=/']
       
    74 
       
    75 Most headers are available in a parsed getter/setter form through
       
    76 properties:
       
    77 
       
    78     >>> res.age = 10
       
    79     >>> res.age, res.headers['age']
       
    80     (10, '10')
       
    81     >>> res.allow = ['GET', 'PUT']
       
    82     >>> res.allow, res.headers['allow']
       
    83     (['GET', 'PUT'], 'GET, PUT')
       
    84     >>> res.cache_control
       
    85     <CacheControl ''>
       
    86     >>> print res.cache_control.max_age
       
    87     None
       
    88     >>> res.cache_control.properties['max-age'] = None
       
    89     >>> print res.cache_control.max_age
       
    90     -1
       
    91     >>> res.cache_control.max_age = 10
       
    92     >>> res.cache_control
       
    93     <CacheControl 'max-age=10'>
       
    94     >>> res.headers['cache-control']
       
    95     'max-age=10'
       
    96     >>> res.cache_control.max_stale = 10
       
    97     Traceback (most recent call last):
       
    98         ...
       
    99     AttributeError: The property max-stale only applies to request Cache-Control
       
   100     >>> res.cache_control = {}
       
   101     >>> res.cache_control
       
   102     <CacheControl ''>
       
   103     >>> res.content_encoding = 'gzip'
       
   104     >>> (res.content_encoding, res.headers['content-encoding'])
       
   105     ('gzip', 'gzip')
       
   106     >>> res.content_language = 'en'
       
   107     >>> (res.content_language, res.headers['content-language'])
       
   108     (['en'], 'en')
       
   109     >>> res.content_location = 'http://localhost:8080'
       
   110     >>> res.headers['content-location']
       
   111     'http://localhost:8080'
       
   112     >>> res.content_range = (0, 100, 1000)
       
   113     >>> (res.content_range, res.headers['content-range'])
       
   114     (<ContentRange bytes 0-101/1000>, 'bytes 0-101/1000')
       
   115     >>> res.date = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
       
   116     >>> (res.date, res.headers['date'])
       
   117     (datetime.datetime(2005, 1, 1, 12, 0, tzinfo=UTC), 'Sat, 01 Jan 2005 12:00:00 GMT')
       
   118     >>> print res.etag
       
   119     None
       
   120     >>> res.etag = 'foo'
       
   121     >>> (res.etag, res.headers['etag'])
       
   122     ('foo', 'foo')
       
   123     >>> res.expires = res.date
       
   124     >>> res.retry_after = 120 # two minutes
       
   125     >>> res.retry_after
       
   126     datetime.datetime(...)
       
   127     >>> res.server = 'Python/foo'
       
   128     >>> res.headers['server']
       
   129     'Python/foo'
       
   130     >>> res.vary = ['Cookie']
       
   131     >>> (res.vary, res.headers['vary'])
       
   132     (['Cookie'], 'Cookie')
       
   133 
       
   134 The location header will try to absolutify itself if you have a
       
   135 request object attached.
       
   136 
       
   137     >>> res.location = '/test.html'
       
   138     >>> from webob import Request
       
   139     >>> res.request = Request.blank('/')
       
   140     >>> res.location
       
   141     'http://localhost/test.html'
       
   142     >>> res.request = None
       
   143     >>> res.location
       
   144     '/test.html'
       
   145     >>> res.request = Request.blank('/')
       
   146     >>> res.location = '/test2.html'
       
   147     >>> res.request = None
       
   148     >>> res.location
       
   149     'http://localhost/test2.html'
       
   150 
       
   151 There's some conditional response handling too (you have to turn on
       
   152 conditioanl_response)::
       
   153 
       
   154     >>> res = Response(conditional_response=True)
       
   155     >>> req = Request.blank('/')
       
   156     >>> res.etag = 'tag'
       
   157     >>> req.if_none_match = 'tag'
       
   158     >>> req.get_response(res)
       
   159     <Response ... 304 Not Modified>
       
   160     >>> res.etag = 'other-tag'
       
   161     >>> req.get_response(res)
       
   162     <Response ... 200 OK>
       
   163     >>> del req.if_none_match
       
   164     >>> req.if_modified_since = datetime(2005, 1, 1, 12, 1, tzinfo=UTC)
       
   165     >>> res.last_modified = datetime(2005, 1, 1, 12, 1, tzinfo=UTC)
       
   166     >>> req.get_response(res)
       
   167     <Response ... 304 Not Modified>
       
   168     >>> res.last_modified = datetime(2006, 1, 1, 12, 1, tzinfo=UTC)
       
   169     >>> req.get_response(res)
       
   170     <Response ... 200 OK>
       
   171     >>> res.last_modified = None
       
   172     >>> req.get_response(res)
       
   173     <Response ... 200 OK>
       
   174 
       
   175 Also range response::
       
   176 
       
   177     >>> res = Response(conditional_response=True)
       
   178     >>> req = Request.blank('/')
       
   179     >>> res.body = '0123456789'
       
   180     >>> req.range = (1, 5)
       
   181     >>> result = req.get_response(res)
       
   182     >>> result.body
       
   183     '1234'
       
   184     >>> result.content_range
       
   185     <ContentRange bytes 1-6/10>
       
   186     >>> tuple(result.content_range)
       
   187     (1, 5, 10)
       
   188     >>> # Now an invalid range:
       
   189     >>> req.range = (0, 20)
       
   190     >>> str(req.range)
       
   191     'bytes=0-21'
       
   192     >>> result = req.get_response(res)
       
   193     >>> result.body
       
   194     '0123456789'
       
   195     >>> print result.content_range
       
   196     None
       
   197 
       
   198 That was easier; we'll try it with a iterator for the body::
       
   199 
       
   200     >>> res = Response(conditional_response=True)
       
   201     >>> res.app_iter = ['01234', '567', '89']
       
   202     >>> req = Request.blank('/')
       
   203     >>> req.range = (1, 5)
       
   204     >>> result = req.get_response(res)
       
   205     >>> # Because we don't know the length of the app_iter, this
       
   206     >>> # doesn't work:
       
   207     >>> result.body
       
   208     '0123456789'
       
   209     >>> print result.content_range
       
   210     None
       
   211     >>> req.range = (5, None)
       
   212     >>> result = req.get_response(res)
       
   213     >>> result.body
       
   214     '56789'
       
   215     >>> result.content_range
       
   216     <ContentRange bytes 5-*/10>
       
   217     >>> # If we set Content-Length then we can use it with an app_iter
       
   218     >>> res.content_length = 10
       
   219     >>> req.range = (1, 5)
       
   220     >>> result = req.get_response(res)
       
   221     >>> result.body
       
   222     '1234'
       
   223     >>> result.content_range
       
   224     <ContentRange bytes 1-6/10>
       
   225     >>> # And trying If-modified-since
       
   226     >>> res.etag = 'foobar'
       
   227     >>> req.if_range = 'foobar'
       
   228     >>> req.if_range
       
   229     <IfRange etag=foobar, date=*>
       
   230     >>> result = req.get_response(res)
       
   231     >>> result.content_range
       
   232     <ContentRange bytes 1-6/10>
       
   233     >>> req.if_range = 'blah'
       
   234     >>> result = req.get_response(res)
       
   235     >>> result.content_range
       
   236     >>> req.if_range = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
       
   237     >>> res.last_modified = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
       
   238     >>> result = req.get_response(res)
       
   239     >>> result.content_range
       
   240     <ContentRange bytes 1-6/10>
       
   241     >>> res.last_modified = datetime(2006, 1, 1, 12, 0, tzinfo=UTC)
       
   242     >>> result = req.get_response(res)
       
   243     >>> result.content_range
       
   244 
       
   245 Some tests of exceptions::
       
   246 
       
   247     >>> from webob import exc
       
   248     >>> res = exc.HTTPNotFound('Not found!')
       
   249     >>> res.exception.content_type = 'text/plain'
       
   250     >>> res.content_type
       
   251     'text/plain'
       
   252     >>> res = exc.HTTPNotModified()
       
   253     >>> res.headers
       
   254     HeaderDict([])