Flows no longer need to be saved between uses.

Also introduces util.positional declarations.

Reviewed in http://codereview.appspot.com/6441056/.

Fixes issue #136.
diff --git a/tests/test_discovery.py b/tests/test_discovery.py
index b1656c4..b2f69c5 100644
--- a/tests/test_discovery.py
+++ b/tests/test_discovery.py
@@ -64,10 +64,17 @@
 
 class DiscoveryErrors(unittest.TestCase):
 
+  def test_tests_should_be_run_with_strict_positional_enforcement(self):
+    try:
+      plus = build('plus', 'v1', None)
+      self.fail("should have raised a TypeError exception over missing http=.")
+    except TypeError:
+      pass
+
   def test_failed_to_parse_discovery_json(self):
     self.http = HttpMock(datafile('malformed.json'), {'status': '200'})
     try:
-      plus = build('plus', 'v1', self.http)
+      plus = build('plus', 'v1', http=self.http)
       self.fail("should have raised an exception over malformed JSON.")
     except InvalidJsonError:
       pass
@@ -103,7 +110,7 @@
       http = HttpMockSequence([
         ({'status': '400'}, file(datafile('zoo.json'), 'r').read()),
         ])
-      zoo = build('zoo', 'v1', http, developerKey='foo',
+      zoo = build('zoo', 'v1', http=http, developerKey='foo',
                   discoveryServiceUrl='http://example.com')
       self.fail('Should have raised an exception.')
     except HttpError, e:
@@ -116,7 +123,7 @@
       http = HttpMockSequence([
         ({'status': '400'}, file(datafile('zoo.json'), 'r').read()),
         ])
-      zoo = build('zoo', 'v1', http, developerKey=None,
+      zoo = build('zoo', 'v1', http=http, developerKey=None,
                   discoveryServiceUrl='http://example.com')
       self.fail('Should have raised an exception.')
     except HttpError, e:
@@ -127,7 +134,7 @@
 
   def test_method_error_checking(self):
     self.http = HttpMock(datafile('plus.json'), {'status': '200'})
-    plus = build('plus', 'v1', self.http)
+    plus = build('plus', 'v1', http=self.http)
 
     # Missing required parameters
     try:
@@ -170,7 +177,7 @@
 
   def test_type_coercion(self):
     http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', http)
+    zoo = build('zoo', 'v1', http=http)
 
     request = zoo.query(
         q="foo", i=1.0, n=1.0, b=0, a=[1,2,3], o={'a':1}, e='bar')
@@ -192,7 +199,7 @@
 
   def test_optional_stack_query_parameters(self):
     http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', http)
+    zoo = build('zoo', 'v1', http=http)
     request = zoo.query(trace='html', fields='description')
 
     parsed = urlparse.urlparse(request.uri)
@@ -202,7 +209,7 @@
 
   def test_string_params_value_of_none_get_dropped(self):
     http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', http)
+    zoo = build('zoo', 'v1', http=http)
     request = zoo.query(trace=None, fields='description')
 
     parsed = urlparse.urlparse(request.uri)
@@ -211,7 +218,7 @@
 
   def test_model_added_query_parameters(self):
     http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', http)
+    zoo = build('zoo', 'v1', http=http)
     request = zoo.animals().get(name='Lion')
 
     parsed = urlparse.urlparse(request.uri)
@@ -221,7 +228,7 @@
 
   def test_fallback_to_raw_model(self):
     http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', http)
+    zoo = build('zoo', 'v1', http=http)
     request = zoo.animals().getmedia(name='Lion')
 
     parsed = urlparse.urlparse(request.uri)
@@ -231,7 +238,7 @@
 
   def test_patch(self):
     http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', http)
+    zoo = build('zoo', 'v1', http=http)
     request = zoo.animals().patch(name='lion', body='{"description": "foo"}')
 
     self.assertEqual(request.method, 'PATCH')
@@ -242,7 +249,7 @@
       ({'status': '200'}, 'echo_request_headers_as_json'),
       ])
     http = tunnel_patch(http)
-    zoo = build('zoo', 'v1', http)
+    zoo = build('zoo', 'v1', http=http)
     resp = zoo.animals().patch(
         name='lion', body='{"description": "foo"}').execute()
 
@@ -250,7 +257,7 @@
 
   def test_plus_resources(self):
     self.http = HttpMock(datafile('plus.json'), {'status': '200'})
-    plus = build('plus', 'v1', self.http)
+    plus = build('plus', 'v1', http=self.http)
     self.assertTrue(getattr(plus, 'activities'))
     self.assertTrue(getattr(plus, 'people'))
 
@@ -258,7 +265,7 @@
     # Zoo should exercise all discovery facets
     # and should also have no future.json file.
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
     self.assertTrue(getattr(zoo, 'animals'))
 
     request = zoo.animals().list(name='bat', projection="full")
@@ -269,7 +276,7 @@
 
   def test_nested_resources(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
     self.assertTrue(getattr(zoo, 'animals'))
     request = zoo.my().favorites().list(max_results="5")
     parsed = urlparse.urlparse(request.uri)
@@ -278,7 +285,7 @@
 
   def test_methods_with_reserved_names(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
     self.assertTrue(getattr(zoo, 'animals'))
     request = zoo.global_().print_().assert_(max_results="5")
     parsed = urlparse.urlparse(request.uri)
@@ -286,7 +293,7 @@
 
   def test_top_level_functions(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
     self.assertTrue(getattr(zoo, 'query'))
     request = zoo.query(q="foo")
     parsed = urlparse.urlparse(request.uri)
@@ -295,20 +302,20 @@
 
   def test_simple_media_uploads(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
     doc = getattr(zoo.animals().insert, '__doc__')
     self.assertTrue('media_body' in doc)
 
   def test_simple_media_upload_no_max_size_provided(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
     request = zoo.animals().crossbreed(media_body=datafile('small.png'))
     self.assertEquals('image/png', request.headers['content-type'])
     self.assertEquals('PNG', request.body[1:4])
 
   def test_simple_media_raise_correct_exceptions(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     try:
       zoo.animals().insert(media_body=datafile('smiley.png'))
@@ -324,7 +331,7 @@
 
   def test_simple_media_good_upload(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     request = zoo.animals().insert(media_body=datafile('small.png'))
     self.assertEquals('image/png', request.headers['content-type'])
@@ -335,7 +342,7 @@
 
   def test_multipart_media_raise_correct_exceptions(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     try:
       zoo.animals().insert(media_body=datafile('smiley.png'), body={})
@@ -351,7 +358,7 @@
 
   def test_multipart_media_good_upload(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     request = zoo.animals().insert(media_body=datafile('small.png'), body={})
     self.assertTrue(request.headers['content-type'].startswith(
@@ -363,14 +370,14 @@
 
   def test_media_capable_method_without_media(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     request = zoo.animals().insert(body={})
     self.assertTrue(request.headers['content-type'], 'application/json')
 
   def test_resumable_multipart_media_good_upload(self):
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
     request = zoo.animals().insert(media_body=media_upload, body={})
@@ -396,7 +403,7 @@
       ({'status': '200'}, '{"foo": "bar"}'),
       ])
 
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEquals(None, body)
     self.assertTrue(isinstance(status, MediaUploadProgress))
     self.assertEquals(13, status.resumable_progress)
@@ -408,13 +415,13 @@
     self.assertEquals(media_upload, request.resumable)
     self.assertEquals(13, request.resumable_progress)
 
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEquals(request.resumable_uri, 'http://upload.example.com/3')
     self.assertEquals(media_upload.size()-1, request.resumable_progress)
     self.assertEquals('{"data": {}}', request.body)
 
     # Final call to next_chunk should complete the upload.
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEquals(body, {"foo": "bar"})
     self.assertEquals(status, None)
 
@@ -422,7 +429,7 @@
   def test_resumable_media_good_upload(self):
     """Not a multipart upload."""
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
     request = zoo.animals().insert(media_body=media_upload, body=None)
@@ -445,7 +452,7 @@
       ({'status': '200'}, '{"foo": "bar"}'),
       ])
 
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEquals(None, body)
     self.assertTrue(isinstance(status, MediaUploadProgress))
     self.assertEquals(13, status.resumable_progress)
@@ -457,13 +464,13 @@
     self.assertEquals(media_upload, request.resumable)
     self.assertEquals(13, request.resumable_progress)
 
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEquals(request.resumable_uri, 'http://upload.example.com/3')
     self.assertEquals(media_upload.size()-1, request.resumable_progress)
     self.assertEquals(request.body, None)
 
     # Final call to next_chunk should complete the upload.
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEquals(body, {"foo": "bar"})
     self.assertEquals(status, None)
 
@@ -471,7 +478,7 @@
   def test_resumable_media_good_upload_from_execute(self):
     """Not a multipart upload."""
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
     request = zoo.animals().insert(media_body=media_upload, body=None)
@@ -491,13 +498,13 @@
       ({'status': '200'}, '{"foo": "bar"}'),
       ])
 
-    body = request.execute(http)
+    body = request.execute(http=http)
     self.assertEquals(body, {"foo": "bar"})
 
   def test_resumable_media_fail_unknown_response_code_first_request(self):
     """Not a multipart upload."""
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
     request = zoo.animals().insert(media_body=media_upload, body=None)
@@ -507,12 +514,12 @@
         'location': 'http://upload.example.com'}, ''),
       ])
 
-    self.assertRaises(ResumableUploadError, request.execute, http)
+    self.assertRaises(ResumableUploadError, request.execute, http=http)
 
   def test_resumable_media_fail_unknown_response_code_subsequent_request(self):
     """Not a multipart upload."""
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     media_upload = MediaFileUpload(datafile('small.png'), resumable=True)
     request = zoo.animals().insert(media_body=media_upload, body=None)
@@ -523,7 +530,7 @@
       ({'status': '400'}, ''),
       ])
 
-    self.assertRaises(HttpError, request.execute, http)
+    self.assertRaises(HttpError, request.execute, http=http)
     self.assertTrue(request._in_error_state)
 
     http = HttpMockSequence([
@@ -533,7 +540,7 @@
         'range': '0-6'}, ''),
       ])
 
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEquals(status.resumable_progress, 7,
       'Should have first checked length and then tried to PUT more.')
     self.assertFalse(request._in_error_state)
@@ -542,14 +549,14 @@
     http = HttpMockSequence([
       ({'status': '400'}, ''),
       ])
-    self.assertRaises(HttpError, request.execute, http)
+    self.assertRaises(HttpError, request.execute, http=http)
     self.assertTrue(request._in_error_state)
 
     # Pretend the last request that 400'd actually succeeded.
     http = HttpMockSequence([
       ({'status': '200'}, '{"foo": "bar"}'),
       ])
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEqual(body, {'foo': 'bar'})
 
   def test_resumable_media_handle_uploads_of_unknown_size(self):
@@ -560,7 +567,7 @@
       ])
 
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     fd = StringIO.StringIO('data goes here')
 
@@ -569,7 +576,7 @@
         fd=fd, mimetype='image/png', chunksize=10, resumable=True)
 
     request = zoo.animals().insert(media_body=upload, body=None)
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEqual(body, {'Content-Range': 'bytes 0-9/*'},
       'Should be 10 out of * bytes.')
 
@@ -581,7 +588,7 @@
       ])
 
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     fd = StringIO.StringIO('data goes here')
 
@@ -590,7 +597,7 @@
         fd=fd, mimetype='image/png', chunksize=15, resumable=True)
 
     request = zoo.animals().insert(media_body=upload, body=None)
-    status, body = request.next_chunk(http)
+    status, body = request.next_chunk(http=http)
     self.assertEqual(body, {'Content-Range': 'bytes 0-13/14'})
 
   def test_resumable_media_handle_resume_of_upload_of_unknown_size(self):
@@ -601,7 +608,7 @@
       ])
 
     self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', self.http)
+    zoo = build('zoo', 'v1', http=self.http)
 
     # Create an upload that doesn't know the full size of the media.
     fd = StringIO.StringIO('data goes here')
@@ -612,7 +619,7 @@
     request = zoo.animals().insert(media_body=upload, body=None)
 
     # Put it in an error state.
-    self.assertRaises(HttpError, request.next_chunk, http)
+    self.assertRaises(HttpError, request.next_chunk, http=http)
 
     http = HttpMockSequence([
       ({'status': '400',
@@ -620,7 +627,7 @@
       ])
     try:
       # Should resume the upload by first querying the status of the upload.
-      request.next_chunk(http)
+      request.next_chunk(http=http)
     except HttpError, e:
       expected = {
           'Content-Range': 'bytes */*',
@@ -634,13 +641,13 @@
 
   def test_next_successful_none_on_no_next_page_token(self):
     self.http = HttpMock(datafile('tasks.json'), {'status': '200'})
-    tasks = build('tasks', 'v1', self.http)
+    tasks = build('tasks', 'v1', http=self.http)
     request = tasks.tasklists().list()
     self.assertEqual(None, tasks.tasklists().list_next(request, {}))
 
   def test_next_successful_with_next_page_token(self):
     self.http = HttpMock(datafile('tasks.json'), {'status': '200'})
-    tasks = build('tasks', 'v1', self.http)
+    tasks = build('tasks', 'v1', http=self.http)
     request = tasks.tasklists().list()
     next_request = tasks.tasklists().list_next(
         request, {'nextPageToken': '123abc'})
@@ -650,7 +657,7 @@
 
   def test_next_with_method_with_no_properties(self):
     self.http = HttpMock(datafile('latitude.json'), {'status': '200'})
-    service = build('latitude', 'v1', self.http)
+    service = build('latitude', 'v1', http=self.http)
     request = service.currentLocation().get()
 
 
@@ -658,7 +665,7 @@
 
   def test_get_media(self):
     http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', http)
+    zoo = build('zoo', 'v1', http=http)
     request = zoo.animals().get_media(name='Lion')
 
     parsed = urlparse.urlparse(request.uri)
@@ -669,7 +676,7 @@
     http = HttpMockSequence([
       ({'status': '200'}, 'standing in for media'),
       ])
-    response = request.execute(http)
+    response = request.execute(http=http)
     self.assertEqual('standing in for media', response)
 
 
diff --git a/tests/test_errors.py b/tests/test_errors.py
index 25e5d2c..c45ce35 100644
--- a/tests/test_errors.py
+++ b/tests/test_errors.py
@@ -59,7 +59,7 @@
     resp, content = fake_response(JSON_ERROR_CONTENT,
         {'status':'400', 'content-type': 'application/json'},
         reason='Failed')
-    error = HttpError(resp, content, 'http://example.org')
+    error = HttpError(resp, content, uri='http://example.org')
     self.assertEqual(str(error), '<HttpError 400 when requesting http://example.org returned "country is required">')
 
   def test_bad_json_body(self):
@@ -75,7 +75,7 @@
     resp, content = fake_response('{',
         {'status':'400', 'content-type': 'application/json'},
         reason='Failure')
-    error = HttpError(resp, content, 'http://example.org')
+    error = HttpError(resp, content, uri='http://example.org')
     self.assertEqual(str(error), '<HttpError 400 when requesting http://example.org returned "Failure">')
 
   def test_missing_message_json_body(self):
diff --git a/tests/test_http.py b/tests/test_http.py
index 9387e3a..45cdaf5 100644
--- a/tests/test_http.py
+++ b/tests/test_http.py
@@ -140,7 +140,7 @@
     self.assertEqual('PNG', new_upload.getbytes(1, 3))
 
   def test_media_inmemory_upload(self):
-    media = MediaInMemoryUpload('abcdef', 'text/plain', chunksize=10,
+    media = MediaInMemoryUpload('abcdef', mimetype='text/plain', chunksize=10,
                                 resumable=True)
     self.assertEqual('text/plain', media.mimetype())
     self.assertEqual(10, media.chunksize())
@@ -149,7 +149,7 @@
     self.assertEqual(6, media.size())
 
   def test_media_inmemory_upload_json_roundtrip(self):
-    media = MediaInMemoryUpload(os.urandom(64), 'text/plain', chunksize=10,
+    media = MediaInMemoryUpload(os.urandom(64), mimetype='text/plain', chunksize=10,
                                 resumable=True)
     data = media.to_json()
     newmedia = MediaInMemoryUpload.new_from_json(data)
@@ -261,7 +261,7 @@
 
   def setUp(self):
     http = HttpMock(datafile('zoo.json'), {'status': '200'})
-    zoo = build('zoo', 'v1', http)
+    zoo = build('zoo', 'v1', http=http)
     self.request = zoo.animals().get_media(name='Lion')
     self.fd = StringIO.StringIO()
 
@@ -587,7 +587,7 @@
         'content-type': 'multipart/mixed; boundary="batch_foobarbaz"'},
        BATCH_RESPONSE),
       ])
-    batch.execute(http)
+    batch.execute(http=http)
     self.assertEqual({'foo': 42}, callbacks.responses['1'])
     self.assertEqual(None, callbacks.exceptions['1'])
     self.assertEqual({'baz': 'qux'}, callbacks.responses['2'])
@@ -604,7 +604,7 @@
         'echo_request_body'),
       ])
     try:
-      batch.execute(http)
+      batch.execute(http=http)
       self.fail('Should raise exception')
     except BatchError, e:
       boundary, _ = e.content.split(None, 1)
@@ -642,7 +642,7 @@
 
     batch.add(self.request1, callback=callbacks.f)
     batch.add(self.request2, callback=callbacks.f)
-    batch.execute(http)
+    batch.execute(http=http)
 
     self.assertEqual({'foo': 42}, callbacks.responses['1'])
     self.assertEqual(None, callbacks.exceptions['1'])
@@ -684,7 +684,7 @@
 
     batch.add(self.request1, callback=callbacks.f)
     batch.add(self.request2, callback=callbacks.f)
-    batch.execute(http)
+    batch.execute(http=http)
 
     self.assertEqual(None, callbacks.responses['1'])
     self.assertEqual(401, callbacks.exceptions['1'].resp.status)
@@ -704,7 +704,7 @@
         'content-type': 'multipart/mixed; boundary="batch_foobarbaz"'},
        BATCH_RESPONSE),
       ])
-    batch.execute(http)
+    batch.execute(http=http)
     self.assertEqual({'foo': 42}, callbacks.responses['1'])
     self.assertEqual({'baz': 'qux'}, callbacks.responses['2'])
 
@@ -719,7 +719,7 @@
         'content-type': 'multipart/mixed; boundary="batch_foobarbaz"'},
        BATCH_ERROR_RESPONSE),
       ])
-    batch.execute(http)
+    batch.execute(http=http)
     self.assertEqual({'foo': 42}, callbacks.responses['1'])
     expected = ('<HttpError 403 when requesting '
         'https://www.googleapis.com/someapi/v1/collection/?foo=bar returned '
diff --git a/tests/test_oauth2client.py b/tests/test_oauth2client.py
index a618674..be94fa1 100644
--- a/tests/test_oauth2client.py
+++ b/tests/test_oauth2client.py
@@ -55,13 +55,16 @@
 
 DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
 
+
 def datafile(filename):
   return os.path.join(DATA_DIR, filename)
 
+
 def load_and_cache(existing_file, fakename, cache_mock):
   client_type, client_info = _loadfile(datafile(existing_file))
   cache_mock.cache[fakename] = {client_type: client_info}
 
+
 class CacheMock(object):
     def __init__(self):
       self.cache = {}
@@ -195,7 +198,7 @@
   def setUp(self):
     user_agent = "fun/2.0"
     self.credentials = self.AssertionCredentialsTestImpl(self.assertion_type,
-        user_agent)
+        user_agent=user_agent)
 
   def test_assertion_body(self):
     body = urlparse.parse_qs(self.credentials._generate_refresh_request_body())
@@ -230,6 +233,7 @@
 
     self.assertRaises(VerifyJwtTokenError, _extract_id_token, jwt)
 
+
 class OAuth2WebServerFlowTest(unittest.TestCase):
 
   def setUp(self):
@@ -237,18 +241,19 @@
         client_id='client_id+1',
         client_secret='secret+1',
         scope='foo',
+        redirect_uri=OOB_CALLBACK_URN,
         user_agent='unittest-sample/1.0',
         )
 
   def test_construct_authorize_url(self):
-    authorize_url = self.flow.step1_get_authorize_url('OOB_CALLBACK_URN')
+    authorize_url = self.flow.step1_get_authorize_url()
 
     parsed = urlparse.urlparse(authorize_url)
     q = parse_qs(parsed[4])
     self.assertEqual('client_id+1', q['client_id'][0])
     self.assertEqual('code', q['response_type'][0])
     self.assertEqual('foo', q['scope'][0])
-    self.assertEqual('OOB_CALLBACK_URN', q['redirect_uri'][0])
+    self.assertEqual(OOB_CALLBACK_URN, q['redirect_uri'][0])
     self.assertEqual('offline', q['access_type'][0])
 
   def test_override_flow_access_type(self):
@@ -257,17 +262,18 @@
         client_id='client_id+1',
         client_secret='secret+1',
         scope='foo',
+        redirect_uri=OOB_CALLBACK_URN,
         user_agent='unittest-sample/1.0',
         access_type='online'
         )
-    authorize_url = flow.step1_get_authorize_url('OOB_CALLBACK_URN')
+    authorize_url = flow.step1_get_authorize_url()
 
     parsed = urlparse.urlparse(authorize_url)
     q = parse_qs(parsed[4])
     self.assertEqual('client_id+1', q['client_id'][0])
     self.assertEqual('code', q['response_type'][0])
     self.assertEqual('foo', q['scope'][0])
-    self.assertEqual('OOB_CALLBACK_URN', q['redirect_uri'][0])
+    self.assertEqual(OOB_CALLBACK_URN, q['redirect_uri'][0])
     self.assertEqual('online', q['access_type'][0])
 
   def test_exchange_failure(self):
@@ -276,7 +282,7 @@
       ])
 
     try:
-      credentials = self.flow.step2_exchange('some random code', http)
+      credentials = self.flow.step2_exchange('some random code', http=http)
       self.fail("should raise exception if exchange doesn't get 200")
     except FlowExchangeError:
       pass
@@ -287,7 +293,7 @@
     ])
 
     try:
-      credentials = self.flow.step2_exchange('some random code', http)
+      credentials = self.flow.step2_exchange('some random code', http=http)
       self.fail("should raise exception if exchange doesn't get 200")
     except FlowExchangeError, e:
       self.assertEquals('invalid_request', str(e))
@@ -305,7 +311,7 @@
       ])
 
     try:
-      credentials = self.flow.step2_exchange('some random code', http)
+      credentials = self.flow.step2_exchange('some random code', http=http)
       self.fail("should raise exception if exchange doesn't get 200")
     except FlowExchangeError, e:
       pass
@@ -318,7 +324,7 @@
        "refresh_token":"8xLOxBtZp8" }"""),
       ])
 
-    credentials = self.flow.step2_exchange('some random code', http)
+    credentials = self.flow.step2_exchange('some random code', http=http)
     self.assertEqual('SlAV32hkKG', credentials.access_token)
     self.assertNotEqual(None, credentials.token_expiry)
     self.assertEqual('8xLOxBtZp8', credentials.refresh_token)
@@ -328,7 +334,7 @@
       ({'status': '200'}, "access_token=SlAV32hkKG&expires_in=3600"),
     ])
 
-    credentials = self.flow.step2_exchange('some random code', http)
+    credentials = self.flow.step2_exchange('some random code', http=http)
     self.assertEqual('SlAV32hkKG', credentials.access_token)
     self.assertNotEqual(None, credentials.token_expiry)
 
@@ -339,7 +345,7 @@
       ({'status': '200'}, "access_token=SlAV32hkKG&expires=3600"),
     ])
 
-    credentials = self.flow.step2_exchange('some random code', http)
+    credentials = self.flow.step2_exchange('some random code', http=http)
     self.assertNotEqual(None, credentials.token_expiry)
 
   def test_exchange_no_expires_in(self):
@@ -348,7 +354,7 @@
        "refresh_token":"8xLOxBtZp8" }"""),
       ])
 
-    credentials = self.flow.step2_exchange('some random code', http)
+    credentials = self.flow.step2_exchange('some random code', http=http)
     self.assertEqual(None, credentials.token_expiry)
 
   def test_urlencoded_exchange_no_expires_in(self):
@@ -358,7 +364,7 @@
       ({'status': '200'}, "access_token=SlAV32hkKG"),
     ])
 
-    credentials = self.flow.step2_exchange('some random code', http)
+    credentials = self.flow.step2_exchange('some random code', http=http)
     self.assertEqual(None, credentials.token_expiry)
 
   def test_exchange_fails_if_no_code(self):
@@ -369,7 +375,7 @@
 
     code = {'error': 'thou shall not pass'}
     try:
-      credentials = self.flow.step2_exchange(code, http)
+      credentials = self.flow.step2_exchange(code, http=http)
       self.fail('should raise exception if no code in dictionary.')
     except FlowExchangeError, e:
       self.assertTrue('shall not pass' in str(e))
@@ -382,7 +388,7 @@
       ])
 
     self.assertRaises(VerifyJwtTokenError, self.flow.step2_exchange,
-      'some random code', http)
+      'some random code', http=http)
 
   def test_exchange_id_token_fail(self):
     body = {'foo': 'bar'}
@@ -396,19 +402,21 @@
        "id_token": "%s"}""" % jwt),
       ])
 
-    credentials = self.flow.step2_exchange('some random code', http)
+    credentials = self.flow.step2_exchange('some random code', http=http)
     self.assertEqual(credentials.id_token, body)
 
-class FlowFromCachedClientsecrets(unittest.TestCase):  
+
+class FlowFromCachedClientsecrets(unittest.TestCase):
 
   def test_flow_from_clientsecrets_cached(self):
     cache_mock = CacheMock()
     load_and_cache('client_secrets.json', 'some_secrets', cache_mock)
-    
-    # flow_from_clientsecrets(filename, scope, message=None, cache=None)
-    flow = flow_from_clientsecrets('some_secrets', '', cache=cache_mock)
+
+    flow = flow_from_clientsecrets(
+        'some_secrets', '', redirect_uri='oob', cache=cache_mock)
     self.assertEquals('foo_client_secret', flow.client_secret)
 
+
 class CredentialsFromCodeTests(unittest.TestCase):
   def setUp(self):
     self.client_id = 'client_id_abc'
@@ -424,8 +432,8 @@
        "expires_in":3600 }"""),
     ])
     credentials = credentials_from_code(self.client_id, self.client_secret,
-                                    self.scope, self.code, self.redirect_uri,
-                                    http)
+        self.scope, self.code, redirect_uri=self.redirect_uri,
+        http=http)
     self.assertEquals(credentials.access_token, 'asdfghjkl')
     self.assertNotEqual(None, credentials.token_expiry)
 
@@ -436,13 +444,12 @@
 
     try:
       credentials = credentials_from_code(self.client_id, self.client_secret,
-                                      self.scope, self.code, self.redirect_uri,
-                                      http)
+          self.scope, self.code, redirect_uri=self.redirect_uri,
+          http=http)
       self.fail("should raise exception if exchange doesn't get 200")
     except FlowExchangeError:
       pass
 
-
   def test_exchange_code_and_file_for_token(self):
     http = HttpMockSequence([
       ({'status': '200'},
@@ -481,7 +488,6 @@
       pass
 
 
-
 class MemoryCacheTests(unittest.TestCase):
 
   def test_get_set_delete(self):
diff --git a/tests/test_oauth2client_appengine.py b/tests/test_oauth2client_appengine.py
index 58f3e55..6774abd 100644
--- a/tests/test_oauth2client_appengine.py
+++ b/tests/test_oauth2client_appengine.py
@@ -55,7 +55,6 @@
 from oauth2client.appengine import CredentialsModel
 from oauth2client.appengine import FlowProperty
 from oauth2client.appengine import OAuth2Decorator
-from oauth2client.appengine import OAuth2Handler
 from oauth2client.appengine import StorageByKeyName
 from oauth2client.appengine import oauth2decorator_from_clientsecrets
 from oauth2client.client import AccessTokenRefreshError
@@ -200,7 +199,8 @@
 
   def test_flow_get_put(self):
     instance = TestFlowModel(
-        flow=flow_from_clientsecrets(datafile('client_secrets.json'), 'foo'),
+        flow=flow_from_clientsecrets(datafile('client_secrets.json'), 'foo',
+                                     redirect_uri='oob'),
         key_name='foo'
         )
     instance.put()
@@ -276,6 +276,14 @@
     self.assertEqual(None, credentials)
     self.assertEqual(None, memcache.get('foo'))
 
+class MockRequest(object):
+  url = 'https://example.org'
+
+  def relative_url(self, rel):
+    return self.url + rel
+
+class MockRequestHandler(object):
+  request = MockRequest()
 
 class DecoratorTests(unittest.TestCase):
 
@@ -312,7 +320,7 @@
 
 
     application = webapp2.WSGIApplication([
-        ('/oauth2callback', OAuth2Handler),
+        ('/oauth2callback', self.decorator.callback_handler()),
         ('/foo_path', TestRequiredHandler),
         webapp2.Route(r'/bar_path/<year:\d{4}>/<month:\d{2}>',
           handler=TestAwareHandler, name='bar')],
@@ -441,6 +449,11 @@
         scope=['foo_scope', 'bar_scope'],
         access_type='offline',
         approval_prompt='force')
+    request_handler = MockRequestHandler()
+    decorator._create_flow(request_handler)
+
+    self.assertEqual('https://example.org/oauth2callback',
+                     decorator.flow.redirect_uri)
     self.assertEqual('offline', decorator.flow.params['access_type'])
     self.assertEqual('force', decorator.flow.params['approval_prompt'])
     self.assertEqual('foo_user_agent', decorator.flow.user_agent)
diff --git a/tests/test_oauth2client_jwt.py b/tests/test_oauth2client_jwt.py
index 65a3410..11162be 100644
--- a/tests/test_oauth2client_jwt.py
+++ b/tests/test_oauth2client_jwt.py
@@ -114,7 +114,7 @@
       ])
 
     contents = verify_id_token(jwt,
-        'some_audience_address@testing.gserviceaccount.com', http)
+        'some_audience_address@testing.gserviceaccount.com', http=http)
     self.assertEqual('billy bob', contents['user'])
     self.assertEqual('data', contents['metadata']['meta'])
 
@@ -126,7 +126,7 @@
       ])
 
     self.assertRaises(VerifyJwtTokenError, verify_id_token, jwt,
-        'some_audience_address@testing.gserviceaccount.com', http)
+        'some_audience_address@testing.gserviceaccount.com', http=http)
 
   def test_verify_id_token_bad_tokens(self):
     private_key = datafile('privatekey.p12')