Repository: Yelp/pyramid-hypernova

Issue:
"stack" property on HypernovaError is formatted inconsistently
When the error is a Python traceback, each element in the list has a trailing newline:
```python
['  File "/nail/home/ckuehl/pg/yelp-main/virtualenv_run/lib/python2.7/site-packages/pyramid_hypernova/batch.py", line 116, in process_responses\n    response_json = r.json()\n',
 '  File "/nail/home/ckuehl/pg/yelp-main/virtualenv_run/lib/python2.7/site-packages/fido/fido.py", line 98, in json\n    return json.loads(self.body.decode(\'utf-8\'))\n',
 '  File "/usr/lib/python2.7/json/__init__.py", line 339, in loads\n    return _default_decoder.decode(s)\n',
[...]
```

When the error comes from the Hypernova server (a JS traceback), each element has no trailing newline:
```python
[u'ReferenceError: Component "yelp_main__DEV__yelp_main__SearchApp__dynamic" not registered',
 u'at YOUR-COMPONENT-DID-NOT-REGISTER_yelp_main__DEV__yelp_main__SearchApp__dynamic:1:1',
 u'at notFound (/nail/home/ckuehl/proj/react_component_renderer/node_modules/hypernova/lib/utils/BatchManager.js:36:15)',
 u'at /nail/home/ckuehl/proj/react_component_renderer/node_modules/hypernova/lib/utils/BatchManager.js:186:35',
 u'at tryCatcher (/nail/home/ckuehl/proj/react_component_renderer/node_modules/bluebird/js/release/util.js:16:23)',
 u'at Promise._settlePromiseFromHandler (/nail/home/ckuehl/proj/react_component_renderer/node_modules/bluebird/js/release/promise.js:512:31)',
[...]
```

Could we normalize these so that it's easier to print these out in a human-readable way?

Comments:

Patch:
diff --git a/pyramid_hypernova/batch.py b/pyramid_hypernova/batch.py
index e4592f1..869b5ea 100644
--- a/pyramid_hypernova/batch.py
+++ b/pyramid_hypernova/batch.py
@@ -131,9 +131,9 @@ class BatchRequest(object):
             __, __, exc_traceback = sys.exc_info()
 
             error = HypernovaError(
-                repr(type(e)),
+                type(e).__name__,
                 str(e),
-                traceback.format_tb(exc_traceback),
+                [line.rstrip('\n') for line in traceback.format_tb(exc_traceback)],
             )
             self.plugin_controller.on_error(error, jobs)
             response = create_fallback_response(jobs, True, self.json_encoder, error)


Test patch:
diff --git a/tests/batch_test.py b/tests/batch_test.py
index 6a9dcf3..1b9f790 100644
--- a/tests/batch_test.py
+++ b/tests/batch_test.py
@@ -331,7 +331,7 @@ class TestBatchRequest(object):
         assert response == {
             token.identifier: JobResult(
                 error=HypernovaError(
-                    name="<class 'fido.exceptions.NetworkError'>",
+                    name='NetworkError',
                     message='oh no',
                     stack=mock.ANY,
                 ),
@@ -475,16 +475,20 @@ class TestBatchRequestLifecycleMethods(object):
         with mock.patch(
             'fido.fetch'
         ) as mock_fetch, mock.patch(
-            'traceback.format_tb'
-        ) as mock_format_tb:
+            'traceback.format_tb',
+            return_value=[
+                'Traceback:\n',
+                '  foo:\n',
+            ],
+        ):
             mock_fetch.return_value.wait.return_value.json.side_effect = NetworkError('oh no')
             batch_request.submit()
 
         spy_plugin_controller.on_error.assert_called_once_with(
             HypernovaError(
-                name="<class 'fido.exceptions.NetworkError'>",
+                name='NetworkError',
                 message='oh no',
-                stack=mock_format_tb.return_value,
+                stack=['Traceback:', '  foo:'],
             ),
             batch_request.jobs,
         )