We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
BatchError is unprintable using default constructor (one string)
This one should be pretty simple, I hope.

Here's the constructor signature: `def __init__(self, reason, resp=None, content=None):`, which doesn't require `resp` to be defined, and I can see it is not defined most of the time, for example, in googleapiclient/http.py.

Then, given the representation method:

```
def __repr__(self):
      return '<BatchError %s "%s">' % (self.resp.status, self.reason)
```

Which is also the string method:

```
__str__ = __repr__
```

This results in unprintable exceptions where `resp` is undefined, which is not very helpful when attempting to understand the error (e.g. #164).


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `googleapiclient/errors.py`
Content:
```
1 # Copyright 2014 Google Inc. All Rights Reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 """Errors for the library.
16 
17 All exceptions defined by the library
18 should be defined in this file.
19 """
20 from __future__ import absolute_import
21 
22 __author__ = 'jcgregorio@google.com (Joe Gregorio)'
23 
24 import json
25 
26 # Oauth2client < 3 has the positional helper in 'util', >= 3 has it
27 # in '_helpers'.
28 try:
29   from oauth2client import util
30 except ImportError:
31   from oauth2client import _helpers as util
32 
33 
34 class Error(Exception):
35   """Base error for this module."""
36   pass
37 
38 
39 class HttpError(Error):
40   """HTTP data was invalid or unexpected."""
41 
42   @util.positional(3)
43   def __init__(self, resp, content, uri=None):
44     self.resp = resp
45     if not isinstance(content, bytes):
46         raise TypeError("HTTP content should be bytes")
47     self.content = content
48     self.uri = uri
49 
50   def _get_reason(self):
51     """Calculate the reason for the error from the response content."""
52     reason = self.resp.reason
53     try:
54       data = json.loads(self.content.decode('utf-8'))
55       if isinstance(data, dict):
56         reason = data['error']['message']
57       elif isinstance(data, list) and len(data) > 0:
58         first_error = data[0]
59         reason = first_error['error']['message']
60     except (ValueError, KeyError, TypeError):
61       pass
62     if reason is None:
63       reason = ''
64     return reason
65 
66   def __repr__(self):
67     if self.uri:
68       return '<HttpError %s when requesting %s returned "%s">' % (
69           self.resp.status, self.uri, self._get_reason().strip())
70     else:
71       return '<HttpError %s "%s">' % (self.resp.status, self._get_reason())
72 
73   __str__ = __repr__
74 
75 
76 class InvalidJsonError(Error):
77   """The JSON returned could not be parsed."""
78   pass
79 
80 
81 class UnknownFileType(Error):
82   """File type unknown or unexpected."""
83   pass
84 
85 
86 class UnknownLinkType(Error):
87   """Link type unknown or unexpected."""
88   pass
89 
90 
91 class UnknownApiNameOrVersion(Error):
92   """No API with that name and version exists."""
93   pass
94 
95 
96 class UnacceptableMimeTypeError(Error):
97   """That is an unacceptable mimetype for this operation."""
98   pass
99 
100 
101 class MediaUploadSizeError(Error):
102   """Media is larger than the method can accept."""
103   pass
104 
105 
106 class ResumableUploadError(HttpError):
107   """Error occured during resumable upload."""
108   pass
109 
110 
111 class InvalidChunkSizeError(Error):
112   """The given chunksize is not valid."""
113   pass
114 
115 class InvalidNotificationError(Error):
116   """The channel Notification is invalid."""
117   pass
118 
119 class BatchError(HttpError):
120   """Error occured during batch operations."""
121 
122   @util.positional(2)
123   def __init__(self, reason, resp=None, content=None):
124     self.resp = resp
125     self.content = content
126     self.reason = reason
127 
128   def __repr__(self):
129       return '<BatchError %s "%s">' % (self.resp.status, self.reason)
130 
131   __str__ = __repr__
132 
133 
134 class UnexpectedMethodError(Error):
135   """Exception raised by RequestMockBuilder on unexpected calls."""
136 
137   @util.positional(1)
138   def __init__(self, methodId=None):
139     """Constructor for an UnexpectedMethodError."""
140     super(UnexpectedMethodError, self).__init__(
141         'Received unexpected call %s' % methodId)
142 
143 
144 class UnexpectedBodyError(Error):
145   """Exception raised by RequestMockBuilder on unexpected bodies."""
146 
147   def __init__(self, expected, provided):
148     """Constructor for an UnexpectedMethodError."""
149     super(UnexpectedBodyError, self).__init__(
150         'Expected: [%s] - Provided: [%s]' % (expected, provided))
151
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/googleapiclient/errors.py b/googleapiclient/errors.py
--- a/googleapiclient/errors.py
+++ b/googleapiclient/errors.py
@@ -126,6 +126,9 @@
     self.reason = reason
 
   def __repr__(self):
+    if getattr(self.resp, 'status', None) is None:
+      return '<BatchError "%s">' % (self.reason)
+    else:
       return '<BatchError %s "%s">' % (self.resp.status, self.reason)
 
   __str__ = __repr__

{"golden_diff": "diff --git a/googleapiclient/errors.py b/googleapiclient/errors.py\n--- a/googleapiclient/errors.py\n+++ b/googleapiclient/errors.py\n@@ -126,6 +126,9 @@\n     self.reason = reason\n \n   def __repr__(self):\n+    if getattr(self.resp, 'status', None) is None:\n+      return '<BatchError \"%s\">' % (self.reason)\n+    else:\n       return '<BatchError %s \"%s\">' % (self.resp.status, self.reason)\n \n   __str__ = __repr__\n", "issue": "BatchError is unprintable using default constructor (one string)\nThis one should be pretty simple, I hope.\n\nHere's the constructor signature: `def __init__(self, reason, resp=None, content=None):`, which doesn't require `resp` to be defined, and I can see it is not defined most of the time, for example, in googleapiclient/http.py.\n\nThen, given the representation method:\n\n```\ndef __repr__(self):\n      return '<BatchError %s \"%s\">' % (self.resp.status, self.reason)\n```\n\nWhich is also the string method:\n\n```\n__str__ = __repr__\n```\n\nThis results in unprintable exceptions where `resp` is undefined, which is not very helpful when attempting to understand the error (e.g. #164).\n\n", "before_files": [{"content": "# Copyright 2014 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Errors for the library.\n\nAll exceptions defined by the library\nshould be defined in this file.\n\"\"\"\nfrom __future__ import absolute_import\n\n__author__ = 'jcgregorio@google.com (Joe Gregorio)'\n\nimport json\n\n# Oauth2client < 3 has the positional helper in 'util', >= 3 has it\n# in '_helpers'.\ntry:\n  from oauth2client import util\nexcept ImportError:\n  from oauth2client import _helpers as util\n\n\nclass Error(Exception):\n  \"\"\"Base error for this module.\"\"\"\n  pass\n\n\nclass HttpError(Error):\n  \"\"\"HTTP data was invalid or unexpected.\"\"\"\n\n  @util.positional(3)\n  def __init__(self, resp, content, uri=None):\n    self.resp = resp\n    if not isinstance(content, bytes):\n        raise TypeError(\"HTTP content should be bytes\")\n    self.content = content\n    self.uri = uri\n\n  def _get_reason(self):\n    \"\"\"Calculate the reason for the error from the response content.\"\"\"\n    reason = self.resp.reason\n    try:\n      data = json.loads(self.content.decode('utf-8'))\n      if isinstance(data, dict):\n        reason = data['error']['message']\n      elif isinstance(data, list) and len(data) > 0:\n        first_error = data[0]\n        reason = first_error['error']['message']\n    except (ValueError, KeyError, TypeError):\n      pass\n    if reason is None:\n      reason = ''\n    return reason\n\n  def __repr__(self):\n    if self.uri:\n      return '<HttpError %s when requesting %s returned \"%s\">' % (\n          self.resp.status, self.uri, self._get_reason().strip())\n    else:\n      return '<HttpError %s \"%s\">' % (self.resp.status, self._get_reason())\n\n  __str__ = __repr__\n\n\nclass InvalidJsonError(Error):\n  \"\"\"The JSON returned could not be parsed.\"\"\"\n  pass\n\n\nclass UnknownFileType(Error):\n  \"\"\"File type unknown or unexpected.\"\"\"\n  pass\n\n\nclass UnknownLinkType(Error):\n  \"\"\"Link type unknown or unexpected.\"\"\"\n  pass\n\n\nclass UnknownApiNameOrVersion(Error):\n  \"\"\"No API with that name and version exists.\"\"\"\n  pass\n\n\nclass UnacceptableMimeTypeError(Error):\n  \"\"\"That is an unacceptable mimetype for this operation.\"\"\"\n  pass\n\n\nclass MediaUploadSizeError(Error):\n  \"\"\"Media is larger than the method can accept.\"\"\"\n  pass\n\n\nclass ResumableUploadError(HttpError):\n  \"\"\"Error occured during resumable upload.\"\"\"\n  pass\n\n\nclass InvalidChunkSizeError(Error):\n  \"\"\"The given chunksize is not valid.\"\"\"\n  pass\n\nclass InvalidNotificationError(Error):\n  \"\"\"The channel Notification is invalid.\"\"\"\n  pass\n\nclass BatchError(HttpError):\n  \"\"\"Error occured during batch operations.\"\"\"\n\n  @util.positional(2)\n  def __init__(self, reason, resp=None, content=None):\n    self.resp = resp\n    self.content = content\n    self.reason = reason\n\n  def __repr__(self):\n      return '<BatchError %s \"%s\">' % (self.resp.status, self.reason)\n\n  __str__ = __repr__\n\n\nclass UnexpectedMethodError(Error):\n  \"\"\"Exception raised by RequestMockBuilder on unexpected calls.\"\"\"\n\n  @util.positional(1)\n  def __init__(self, methodId=None):\n    \"\"\"Constructor for an UnexpectedMethodError.\"\"\"\n    super(UnexpectedMethodError, self).__init__(\n        'Received unexpected call %s' % methodId)\n\n\nclass UnexpectedBodyError(Error):\n  \"\"\"Exception raised by RequestMockBuilder on unexpected bodies.\"\"\"\n\n  def __init__(self, expected, provided):\n    \"\"\"Constructor for an UnexpectedMethodError.\"\"\"\n    super(UnexpectedBodyError, self).__init__(\n        'Expected: [%s] - Provided: [%s]' % (expected, provided))\n", "path": "googleapiclient/errors.py"}], "after_files": [{"content": "# Copyright 2014 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Errors for the library.\n\nAll exceptions defined by the library\nshould be defined in this file.\n\"\"\"\nfrom __future__ import absolute_import\n\n__author__ = 'jcgregorio@google.com (Joe Gregorio)'\n\nimport json\n\n# Oauth2client < 3 has the positional helper in 'util', >= 3 has it\n# in '_helpers'.\ntry:\n  from oauth2client import util\nexcept ImportError:\n  from oauth2client import _helpers as util\n\n\nclass Error(Exception):\n  \"\"\"Base error for this module.\"\"\"\n  pass\n\n\nclass HttpError(Error):\n  \"\"\"HTTP data was invalid or unexpected.\"\"\"\n\n  @util.positional(3)\n  def __init__(self, resp, content, uri=None):\n    self.resp = resp\n    if not isinstance(content, bytes):\n        raise TypeError(\"HTTP content should be bytes\")\n    self.content = content\n    self.uri = uri\n\n  def _get_reason(self):\n    \"\"\"Calculate the reason for the error from the response content.\"\"\"\n    reason = self.resp.reason\n    try:\n      data = json.loads(self.content.decode('utf-8'))\n      if isinstance(data, dict):\n        reason = data['error']['message']\n      elif isinstance(data, list) and len(data) > 0:\n        first_error = data[0]\n        reason = first_error['error']['message']\n    except (ValueError, KeyError, TypeError):\n      pass\n    if reason is None:\n      reason = ''\n    return reason\n\n  def __repr__(self):\n    if self.uri:\n      return '<HttpError %s when requesting %s returned \"%s\">' % (\n          self.resp.status, self.uri, self._get_reason().strip())\n    else:\n      return '<HttpError %s \"%s\">' % (self.resp.status, self._get_reason())\n\n  __str__ = __repr__\n\n\nclass InvalidJsonError(Error):\n  \"\"\"The JSON returned could not be parsed.\"\"\"\n  pass\n\n\nclass UnknownFileType(Error):\n  \"\"\"File type unknown or unexpected.\"\"\"\n  pass\n\n\nclass UnknownLinkType(Error):\n  \"\"\"Link type unknown or unexpected.\"\"\"\n  pass\n\n\nclass UnknownApiNameOrVersion(Error):\n  \"\"\"No API with that name and version exists.\"\"\"\n  pass\n\n\nclass UnacceptableMimeTypeError(Error):\n  \"\"\"That is an unacceptable mimetype for this operation.\"\"\"\n  pass\n\n\nclass MediaUploadSizeError(Error):\n  \"\"\"Media is larger than the method can accept.\"\"\"\n  pass\n\n\nclass ResumableUploadError(HttpError):\n  \"\"\"Error occured during resumable upload.\"\"\"\n  pass\n\n\nclass InvalidChunkSizeError(Error):\n  \"\"\"The given chunksize is not valid.\"\"\"\n  pass\n\nclass InvalidNotificationError(Error):\n  \"\"\"The channel Notification is invalid.\"\"\"\n  pass\n\nclass BatchError(HttpError):\n  \"\"\"Error occured during batch operations.\"\"\"\n\n  @util.positional(2)\n  def __init__(self, reason, resp=None, content=None):\n    self.resp = resp\n    self.content = content\n    self.reason = reason\n\n  def __repr__(self):\n    if getattr(self.resp, 'status', None) is None:\n      return '<BatchError \"%s\">' % (self.reason)\n    else:\n      return '<BatchError %s \"%s\">' % (self.resp.status, self.reason)\n\n  __str__ = __repr__\n\n\nclass UnexpectedMethodError(Error):\n  \"\"\"Exception raised by RequestMockBuilder on unexpected calls.\"\"\"\n\n  @util.positional(1)\n  def __init__(self, methodId=None):\n    \"\"\"Constructor for an UnexpectedMethodError.\"\"\"\n    super(UnexpectedMethodError, self).__init__(\n        'Received unexpected call %s' % methodId)\n\n\nclass UnexpectedBodyError(Error):\n  \"\"\"Exception raised by RequestMockBuilder on unexpected bodies.\"\"\"\n\n  def __init__(self, expected, provided):\n    \"\"\"Constructor for an UnexpectedMethodError.\"\"\"\n    super(UnexpectedBodyError, self).__init__(\n        'Expected: [%s] - Provided: [%s]' % (expected, provided))\n", "path": "googleapiclient/errors.py"}]}