Repository: pypa/pip

Issue:
crash when `sys.stdin` is `None` in subversion.py
**Environment**

* pip version: 19.2.3
* Python version: 3.7.4
* OS: archlinux

**Description**

The code that determines if to use interactive mode in [subversion.py](https://github.com/pypa/pip/blob/master/src/pip/_internal/vcs/subversion.py#L191) breaks when `sys.stdin` is `None`

**Expected behavior**

Does not crash.

**How to Reproduce**

(On linux)

1. Run: `virtualenv -p python3 env`
1. Run: `source env/bin/activate`
1. Run: `python -c 'import pip._internal as pip' 0<&-` (this simulates a `None` `sys.stdin`)

**Output**

```
$ virtualenv -p python3 env
Running virtualenv with interpreter /usr/bin/python3
Using base prefix '/usr'
New python executable in /tmp/env/bin/python3
Also creating executable in /tmp/env/bin/python
Installing setuptools, pip, wheel...
done.
$ source env/bin/activate
(env) $ python -c 'import pip._internal as pip' 0<&-
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/__init__.py", line 40, in <module>
    from pip._internal.cli.autocompletion import autocomplete
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/cli/autocompletion.py", line 8, in <module>
    from pip._internal.cli.main_parser import create_main_parser
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/cli/main_parser.py", line 11, in <module>
    from pip._internal.commands import (
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/commands/__init__.py", line 6, in <module>
    from pip._internal.commands.completion import CompletionCommand
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/commands/completion.py", line 6, in <module>
    from pip._internal.cli.base_command import Command
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/cli/base_command.py", line 21, in <module>
    from pip._internal.download import PipSession
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/download.py", line 47, in <module>
    from pip._internal.vcs import vcs
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/vcs/__init__.py", line 12, in <module>
    import pip._internal.vcs.subversion  # noqa: F401
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/vcs/subversion.py", line 314, in <module>
    vcs.register(Subversion)
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/vcs/versioncontrol.py", line 165, in register
    self._registry[cls.name] = cls()
  File "/tmp/env/lib/python3.7/site-packages/pip/_internal/vcs/subversion.py", line 180, in __init__
    use_interactive = sys.stdin.isatty()
AttributeError: 'NoneType' object has no attribute 'isatty'
(env) $ 

```

**Notes**

And in case you're wondering how I got to this internal API: I'm running (on AWS Lambda) [awslimitchecker](https://github.com/jantman/awslimitchecker), which uses [versionfinder](https://github.com/jantman/versionfinder), which [uses pip](https://github.com/jantman/versionfinder/blob/master/versionfinder/versionfinder.py#L48)


Discussion:

Resolving patch:
diff --git a/src/pip/_internal/utils/misc.py b/src/pip/_internal/utils/misc.py
--- a/src/pip/_internal/utils/misc.py
+++ b/src/pip/_internal/utils/misc.py
@@ -864,3 +864,10 @@ def protect_pip_from_modification_on_windows(modifying_pip):
             'To modify pip, please run the following command:\n{}'
             .format(" ".join(new_command))
         )
+
+
+def is_console_interactive():
+    # type: () -> bool
+    """Is this console interactive?
+    """
+    return sys.stdin is not None and sys.stdin.isatty()
diff --git a/src/pip/_internal/vcs/subversion.py b/src/pip/_internal/vcs/subversion.py
--- a/src/pip/_internal/vcs/subversion.py
+++ b/src/pip/_internal/vcs/subversion.py
@@ -6,11 +6,11 @@
 import logging
 import os
 import re
-import sys
 
 from pip._internal.utils.logging import indent_log
 from pip._internal.utils.misc import (
     display_path,
+    is_console_interactive,
     rmtree,
     split_auth_from_netloc,
 )
@@ -188,7 +188,7 @@ def is_commit_id_equal(cls, dest, name):
     def __init__(self, use_interactive=None):
         # type: (bool) -> None
         if use_interactive is None:
-            use_interactive = sys.stdin.isatty()
+            use_interactive = is_console_interactive()
         self.use_interactive = use_interactive
 
         # This member is used to cache the fetched version of the current


Test patch:
diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py
--- a/tests/unit/test_utils.py
+++ b/tests/unit/test_utils.py
@@ -39,6 +39,7 @@
     get_prog,
     hide_url,
     hide_value,
+    is_console_interactive,
     normalize_path,
     normalize_version_info,
     parse_netloc,
@@ -971,3 +972,18 @@ def test_make_setuptools_shim_args__unbuffered_output(unbuffered_output):
         unbuffered_output=unbuffered_output
     )
     assert ('-u' in args) == unbuffered_output
+
+
+@pytest.mark.parametrize('isatty,no_stdin,expected', [
+    (True, False, True),
+    (False, False, False),
+    (True, True, False),
+    (False, True, False),
+])
+def test_is_console_interactive(monkeypatch, isatty, no_stdin, expected):
+    monkeypatch.setattr(sys.stdin, 'isatty', Mock(return_value=isatty))
+
+    if no_stdin:
+        monkeypatch.setattr(sys, 'stdin', None)
+
+    assert is_console_interactive() is expected