Repository: peterbe/hashin

Issue:
Python version typos generate messy exception
Currently, if I specify the python version improperly, or there is no package for that version, I get an exception thrown:
```
$ hashin -p python2.8 -v -r requirements.txt pyasn1==0.2.3
https://pypi.python.org/pypi/pyasn1/json
Traceback (most recent call last):
  File "/Users/hwine/.pyenv/versions/tools3/bin/hashin", line 11, in <module>
    sys.exit(main())
  File "/Users/hwine/.pyenv/versions/3.6.1/envs/tools3/lib/python3.6/site-packages/hashin.py", line 432, in main
    verbose=args.verbose,
  File "/Users/hwine/.pyenv/versions/3.6.1/envs/tools3/lib/python3.6/site-packages/hashin.py", line 104, in run
    run_single_package(spec, *args, **kwargs)
  File "/Users/hwine/.pyenv/versions/3.6.1/envs/tools3/lib/python3.6/site-packages/hashin.py", line 127, in run_single_package
    algorithm=algorithm
  File "/Users/hwine/.pyenv/versions/3.6.1/envs/tools3/lib/python3.6/site-packages/hashin.py", line 399, in get_package_hashes
    python_versions
hashin.PackageError: No releases could be found for 0.2.3 matching Python versions ['python2.8']
```

The last line is great! The traceback doesn't help much in this case.

Discussion:

Patch:
diff --git a/hashin.py b/hashin.py
index 6856bcb..f2b3c1e 100755
--- a/hashin.py
+++ b/hashin.py
@@ -430,13 +430,17 @@ def main():
 
     args = parser.parse_args()
 
-    return run(
-        args.packages,
-        args.requirements_file,
-        args.algorithm,
-        args.python_version,
-        verbose=args.verbose,
-    )
+    try:
+        return run(
+            args.packages,
+            args.requirements_file,
+            args.algorithm,
+            args.python_version,
+            verbose=args.verbose,
+        )
+    except PackageError as exception:
+        print(str(exception), file=sys.stderr)
+        return 1
 
 
 if __name__ == '__main__':


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index af232ad..10e6206 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -142,6 +142,18 @@ class Tests(TestCase):
             'sha256'
         )
 
+    @mock.patch('hashin.parser')
+    @mock.patch('hashin.sys')
+    @mock.patch('hashin.run')
+    def test_main_packageerrors_stderr(self, mock_run, mock_sys, mock_parser):
+        # Doesn't matter so much what, just make sure it breaks
+        mock_run.side_effect = hashin.PackageError('Some message here')
+
+        error = hashin.main()
+        self.assertEqual(error, 1)
+        mock_sys.stderr.write.assert_any_call('Some message here')
+        mock_sys.stderr.write.assert_any_call('\n')
+
     def test_amend_requirements_content_new(self):
         requirements = """
 # empty so far