Repository: unnonouno/jqp

Issue:
Error handling
Don't show stacktrace.

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/8370776/badge)](https://coveralls.io/builds/8370776)

Coverage increased (+14.3%) to 84.848% when pulling **d332fb358942fb35d8d2c960728665cc126f6192 on error-handling** into **89b6ea235226cbc51f3f47f8051bcd8305ff447f on master**.


Patch:
diff --git a/jqp/__init__.py b/jqp/__init__.py
index 9638c44..cdcc02e 100644
--- a/jqp/__init__.py
+++ b/jqp/__init__.py
@@ -6,19 +6,44 @@ import sys
 __version__ = '0.0.0.1'
 
 
+def _exit(error, return_code, message):
+    sys.stderr.write(message)
+    sys.stderr.write('\nOiginal error: ')
+    sys.stderr.write(str(error))
+    sys.stderr.write('\n')
+    sys.exit(return_code)
+
+
 def run(in_io, out_io, cmd):
-    for line in in_io:
+    for i, line in enumerate(in_io):
         if line.strip() == '':
             continue
-        js = json.loads(line)
-        out = eval(cmd, {'j': js})
-        json.dump(out, out_io)
+
+        line_no = i + 1
+        try:
+            js = json.loads(line)
+        except Exception as e:
+            _exit(e, 4, 'Parse error: line %d' % line_no)
+
+        try:
+            out = eval(cmd, {'j': js})
+        except Exception as e:
+            _exit(e, 3, 'Cannot execute command: line %d' % line_no)
+
+        try:
+            json.dump(out, out_io)
+        except Exception as e:
+            _exit(e, 3, 'Cannot dump result: line %d' % line_no)
+
         out_io.write('\n')
 
 
 def main():
     parser = argparse.ArgumentParser()
     parser.add_argument('cmd')
+    parser.add_argument(
+        '--version', action='version', version='jqp %s' % __version__,
+        help='show version and exit')
     args = parser.parse_args()
 
     run(sys.stdin, sys.stdout, args.cmd)


Test patch:
diff --git a/tests/run_test.py b/tests/run_test.py
index 185ce17..31ceb87 100644
--- a/tests/run_test.py
+++ b/tests/run_test.py
@@ -15,3 +15,24 @@ class RunTest(unittest.TestCase):
         outputs = StringIO()
         jqp.run(inputs, outputs, 'j["name"]')
         self.assertEqual(outputs.getvalue(), '"Taro"\n')
+
+    def test_parse_error(self):
+        inputs = StringIO('invalid\n')
+        outputs = StringIO()
+        with self.assertRaises(SystemExit) as e:
+            jqp.run(inputs, outputs, 'j')
+        self.assertEqual(e.exception.code, 4)
+
+    def test_execution_error(self):
+        inputs = StringIO('1\n')
+        outputs = StringIO()
+        with self.assertRaises(SystemExit) as e:
+            jqp.run(inputs, outputs, 'invalid')
+        self.assertEqual(e.exception.code, 3)
+
+    def test_dump_error(self):
+        inputs = StringIO('1\n')
+        outputs = StringIO()
+        with self.assertRaises(SystemExit) as e:
+            jqp.run(inputs, outputs, 'lambda: 0')
+        self.assertEqual(e.exception.code, 3)