Make batch errors align with normal errors.

Fixes issue #169.

Reviewed in http://codereview.appspot.com/6444046/.
diff --git a/apiclient/errors.py b/apiclient/errors.py
index b6ee9a5..b58d97f 100644
--- a/apiclient/errors.py
+++ b/apiclient/errors.py
@@ -54,7 +54,7 @@
   def __repr__(self):
     if self.uri:
       return '<HttpError %s when requesting %s returned "%s">' % (
-          self.resp.status, self.uri, self._get_reason())
+          self.resp.status, self.uri, self._get_reason().strip())
     else:
       return '<HttpError %s "%s">' % (self.resp.status, self._get_reason())
 
diff --git a/apiclient/http.py b/apiclient/http.py
index 1dfe36c..96d7a14 100644
--- a/apiclient/http.py
+++ b/apiclient/http.py
@@ -649,7 +649,6 @@
       resp, content = http.request(self.uri, self.method,
                                    body=self.body,
                                    headers=self.headers)
-
       if resp.status >= 300:
         raise HttpError(resp, content, self.uri)
     return self.postproc(resp, content)
@@ -1185,6 +1184,8 @@
       response = None
       exception = None
       try:
+        if resp.status >= 300:
+          raise HttpError(resp, content, request.uri)
         response = request.postproc(resp, content)
       except HttpError, e:
         exception = e
diff --git a/tests/test_http.py b/tests/test_http.py
index 3b4e7f8..95de47a 100644
--- a/tests/test_http.py
+++ b/tests/test_http.py
@@ -381,6 +381,44 @@
 --batch_foobarbaz--"""
 
 
+BATCH_ERROR_RESPONSE = """--batch_foobarbaz
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: <randomness+1>
+
+HTTP/1.1 200 OK
+Content-Type application/json
+Content-Length: 14
+ETag: "etag/pony"\r\n\r\n{"foo": 42}
+
+--batch_foobarbaz
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: <randomness+2>
+
+HTTP/1.1 403 Access Not Configured
+Content-Type application/json
+Content-Length: 14
+ETag: "etag/sheep"\r\n\r\nContent-Length: 245
+
+{
+ "error": {
+  "errors": [
+   {
+    "domain": "usageLimits",
+    "reason": "accessNotConfigured",
+    "message": "Access Not Configured",
+    "debugInfo": "QuotaState: BLOCKED"
+   }
+  ],
+  "code": 403,
+  "message": "Access Not Configured"
+ }
+}
+
+--batch_foobarbaz--"""
+
+
 BATCH_RESPONSE_WITH_401 = """--batch_foobarbaz
 Content-Type: application/http
 Content-Transfer-Encoding: binary
@@ -670,6 +708,23 @@
     self.assertEqual({'foo': 42}, callbacks.responses['1'])
     self.assertEqual({'baz': 'qux'}, callbacks.responses['2'])
 
+  def test_execute_http_error(self):
+    callbacks = Callbacks()
+    batch = BatchHttpRequest(callback=callbacks.f)
+
+    batch.add(self.request1)
+    batch.add(self.request2)
+    http = HttpMockSequence([
+      ({'status': '200',
+        'content-type': 'multipart/mixed; boundary="batch_foobarbaz"'},
+       BATCH_ERROR_RESPONSE),
+      ])
+    batch.execute(http)
+    self.assertEqual({'foo': 42}, callbacks.responses['1'])
+    expected = ('<HttpError 403 when requesting '
+        'https://www.googleapis.com/someapi/v1/collection/?foo=bar returned '
+        '"Access Not Configured">')
+    self.assertEqual(expected, str(callbacks.exceptions['2']))
 
 if __name__ == '__main__':
   unittest.main()