Repository: jpadilla/pyjwt

Issue:
pyjwt decode --verify CLI hang 
$ pyjwt -v
pyjwt 1.5.3


$ pyjwt decode --no-verify eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg
^CTraceback (most recent call last):
  File "/usr/local/bin/pyjwt", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/jwt/__main__.py", line 157, in main
    output = arguments.func(arguments)
  File "/usr/local/lib/python2.7/dist-packages/jwt/__main__.py", line 58, in decode_payload
    token = sys.stdin.read()

$  pyjwt decode --no-verify eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg
^CTraceback (most recent call last):
  File "/Users/v612996/anaconda/bin/pyjwt", line 11, in <module>
    sys.exit(main())
  File "/Users/v612996/anaconda/lib/python3.6/site-packages/jwt/__main__.py", line 157, in main
    output = arguments.func(arguments)
  File "/Users/v612996/anaconda/lib/python3.6/site-packages/jwt/__main__.py", line 58, in decode_payload
    token = sys.stdin.read()
KeyboardInterrupt
$ python --version
Python 3.6.0 :: Anaconda custom (x86_64)

But the same token decoded perfectly under python 2.6 interpreter: 
>>> jwt.decode(encoded,verify=False)
{u'some': u'payload'}


What is the work around of "pyjwt decode --no-verify" hang in the CLI? 







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

Coverage decreased (-0.4%) to 99.552% when pulling **09cbf0634e47ee97b93eefae7ef8fa44d8682bc0 on fix-298** into **e1e4d02c5d9499bcd59403fff2ad73d67cdc8af4 on master**.

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

Coverage decreased (-0.4%) to 99.552% when pulling **09cbf0634e47ee97b93eefae7ef8fa44d8682bc0 on fix-298** into **e1e4d02c5d9499bcd59403fff2ad73d67cdc8af4 on master**.

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

Coverage decreased (-0.1%) to 99.851% when pulling **99c1ee928af045c9b15fdce9c60cb4fbf6157ed1 on fix-298** into **e1e4d02c5d9499bcd59403fff2ad73d67cdc8af4 on master**.

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

Coverage remained the same at 100.0% when pulling **8d104bc73c8b7ec1de7d724ff0a8c3be83e1893d on fix-298** into **e1e4d02c5d9499bcd59403fff2ad73d67cdc8af4 on master**.


Patch:
diff --git a/.gitignore b/.gitignore
index 9672a5b..a6f0fb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ develop-eggs/
 dist/
 downloads/
 eggs/
+.eggs/
 lib/
 lib64/
 parts/
diff --git a/jwt/__main__.py b/jwt/__main__.py
index 52e7abf..396dc0d 100644
--- a/jwt/__main__.py
+++ b/jwt/__main__.py
@@ -54,10 +54,13 @@ def encode_payload(args):
 
 def decode_payload(args):
     try:
-        if sys.stdin.isatty():
-            token = sys.stdin.read()
-        else:
+        if args.token:
             token = args.token
+        else:
+            if sys.stdin.isatty():
+                token = sys.stdin.readline().strip()
+            else:
+                raise IOError('Cannot read from stdin: terminal not a TTY')
 
         token = token.encode('utf-8')
         data = decode(token, key=args.key, verify=args.verify)
@@ -133,7 +136,10 @@ def build_argparser():
 
     # Decode subcommand
     decode_parser = subparsers.add_parser('decode', help='use to decode a supplied JSON web token')
-    decode_parser.add_argument('token', help='JSON web token to decode.')
+    decode_parser.add_argument(
+        'token',
+        help='JSON web token to decode.',
+        nargs='?')
 
     decode_parser.add_argument(
         '-n', '--no-verify',


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index f08cf6b..715c2f1 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -57,6 +57,37 @@ class TestCli:
 
         assert 'There was an error decoding the token' in str(excinfo.value)
 
+    def test_decode_payload_terminal_tty(self, monkeypatch):
+        encode_args = [
+            '--key=secret-key',
+            'encode',
+            'name=hello-world',
+        ]
+        parser = build_argparser()
+        parsed_encode_args = parser.parse_args(encode_args)
+        token = encode_payload(parsed_encode_args)
+
+        decode_args = ['--key=secret-key', 'decode']
+        parsed_decode_args = parser.parse_args(decode_args)
+
+        monkeypatch.setattr(sys.stdin, 'isatty', lambda: True)
+        monkeypatch.setattr(sys.stdin, 'readline', lambda:  token)
+
+        actual = json.loads(decode_payload(parsed_decode_args))
+        assert actual['name'] == 'hello-world'
+
+    def test_decode_payload_raises_terminal_not_a_tty(self, monkeypatch):
+        decode_args = ['--key', '1234', 'decode']
+        parser = build_argparser()
+        args = parser.parse_args(decode_args)
+
+        monkeypatch.setattr(sys.stdin, 'isatty', lambda: False)
+
+        with pytest.raises(IOError) as excinfo:
+            decode_payload(args)
+            assert 'Cannot read from stdin: terminal not a TTY' \
+                in str(excinfo.value)
+
     @pytest.mark.parametrize('key,name,job,exp,verify', [
         ('1234', 'Vader', 'Sith', None, None),
         ('4567', 'Anakin', 'Jedi', '+1', None),