Repository: r1chardj0n3s/pip-check-reqs

Issue:
Make --version show which interpreter we are running from (and -V alias)
`pip` has this nice feature that helps a lot with debugging virtualenv issues:

```
> pip -V
pip 21.2.2 from /home/mrmino/.pyenv/versions/3.9.7/lib/python3.9/site-packages/pip (python 3.9)
```

Since `pip-check-reqs` is working in a similar regime, where wrong virtualenv can lead to a lot of confusion, it would be nice if our `--version` reported this information too.
Adding -V alias for this would make it more intuitive.

These kinds of errors are more common than one would think, since after executing `pip install pip-check-reqs`, a `pip-missing-reqs` can still point to a script from another environment - shells cache command paths, so until user does `hash -d` (or `rehash` in ZSH), they cannot be sure which environment `pip-check-reqs` is running from.

Discussion:

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index cd4208d..0b7436d 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,10 @@ Release History
 
 - Added `python_requires` to metadata; from now on, releases of
   `pip-check-reqs` are marked as compatible with Python 3.6.1 and up.
+- Made `--version` flag show interpretter version and path to the package which
+  pip-check-reqs is running from, similar to information shown by `pip
+  --version`.
+- `-V` is now an alias of `--version`.
 
 2.3.2
 
diff --git a/pip_check_reqs/common.py b/pip_check_reqs/common.py
index c34ba82..822b8e1 100644
--- a/pip_check_reqs/common.py
+++ b/pip_check_reqs/common.py
@@ -4,10 +4,16 @@ import imp
 import logging
 import os
 import re
+import sys
+
+from pathlib import Path
 from typing import Container, Optional, List, cast
 
 from packaging.utils import canonicalize_name
 from packaging.markers import Marker
+
+from . import __version__
+
 # Between different versions of pip the location of PipSession has changed.
 try:
     from pip._internal.network.session import PipSession
@@ -248,3 +254,11 @@ def ignorer(ignore_cfg):
         return False
 
     return f
+
+
+def version_info():
+    return "pip-check-reqs {} from {} (python {})".format(
+        __version__,
+        str((Path(__file__) / '..').resolve()),
+        "{}.{}.{}".format(*sys.version_info),
+    )
diff --git a/pip_check_reqs/find_extra_reqs.py b/pip_check_reqs/find_extra_reqs.py
index 3e253b3..1834afe 100644
--- a/pip_check_reqs/find_extra_reqs.py
+++ b/pip_check_reqs/find_extra_reqs.py
@@ -8,7 +8,7 @@ import sys
 from packaging.utils import canonicalize_name
 from pip._internal.commands.show import search_packages_info
 from pip_check_reqs import common
-from pip_check_reqs.common import get_installed_distributions
+from pip_check_reqs.common import get_installed_distributions, version_info
 
 log = logging.getLogger(__name__)
 
@@ -82,8 +82,6 @@ def find_extra_reqs(options, requirements_filename):
 
 
 def main():
-    from pip_check_reqs import __version__
-
     usage = 'usage: %prog [options] files or directories'
     parser = optparse.OptionParser(usage)
     parser.add_option("--requirements-file",
@@ -129,7 +127,7 @@ def main():
                       action="store_true",
                       default=False,
                       help="be *really* verbose")
-    parser.add_option("--version",
+    parser.add_option("-V", "--version",
                       dest="version",
                       action="store_true",
                       default=False,
@@ -138,7 +136,8 @@ def main():
     (options, args) = parser.parse_args()
 
     if options.version:
-        sys.exit(__version__)
+        print(version_info())
+        sys.exit(0)
 
     if not args:
         parser.error("no source files or directories specified")
@@ -160,7 +159,7 @@ def main():
     log.setLevel(level)
     common.log.setLevel(level)
 
-    log.info('using pip_check_reqs-%s from %s', __version__, __file__)
+    log.info(version_info())
 
     extras = find_extra_reqs(
         options=options,
diff --git a/pip_check_reqs/find_missing_reqs.py b/pip_check_reqs/find_missing_reqs.py
index 9369637..7f0d0c4 100644
--- a/pip_check_reqs/find_missing_reqs.py
+++ b/pip_check_reqs/find_missing_reqs.py
@@ -15,7 +15,7 @@ except ImportError:  # pragma: no cover
 from pip._internal.req.req_file import parse_requirements
 
 from pip_check_reqs import common
-from pip_check_reqs.common import get_installed_distributions
+from pip_check_reqs.common import get_installed_distributions, version_info
 
 log = logging.getLogger(__name__)
 
@@ -102,8 +102,6 @@ def find_missing_reqs(options, requirements_filename):
 
 
 def main():
-    from pip_check_reqs import __version__
-
     usage = 'usage: %prog [options] files or directories'
     parser = optparse.OptionParser(usage)
     parser.add_option("--requirements-file",
@@ -136,7 +134,7 @@ def main():
                       action="store_true",
                       default=False,
                       help="be *really* verbose")
-    parser.add_option("--version",
+    parser.add_option("-V", "--version",
                       dest="version",
                       action="store_true",
                       default=False,
@@ -145,7 +143,8 @@ def main():
     (options, args) = parser.parse_args()
 
     if options.version:
-        sys.exit(__version__)
+        print(version_info())
+        sys.exit(0)
 
     if not args:
         parser.error("no source files or directories specified")
@@ -166,7 +165,7 @@ def main():
     log.setLevel(level)
     common.log.setLevel(level)
 
-    log.info('using pip_check_reqs-%s from %s', __version__, __file__)
+    log.info(version_info())
 
     missing = find_missing_reqs(
         options=options,


Test patch:
diff --git a/tests/test_common.py b/tests/test_common.py
index 4752a65..93090a6 100644
--- a/tests/test_common.py
+++ b/tests/test_common.py
@@ -8,7 +8,7 @@ from pathlib import Path
 import pytest
 import pretend
 
-from pip_check_reqs import common
+from pip_check_reqs import common, __version__
 
 
 @pytest.mark.parametrize(
@@ -225,3 +225,7 @@ def test_find_imported_modules_sets_encoding_to_utf8_when_reading(tmp_path):
     common.__builtins__['open'] = original_open
 
     assert used_encoding == expected_encoding
+
+
+def test_version_info_shows_version_number():
+    assert __version__ in common.version_info()
diff --git a/tests/test_find_extra_reqs.py b/tests/test_find_extra_reqs.py
index 1a8f086..9434859 100644
--- a/tests/test_find_extra_reqs.py
+++ b/tests/test_find_extra_reqs.py
@@ -8,7 +8,7 @@ from pathlib import Path
 import pytest
 import pretend
 
-from pip_check_reqs import find_extra_reqs, common, __version__
+from pip_check_reqs import find_extra_reqs, common
 
 
 @pytest.fixture
@@ -168,11 +168,11 @@ def test_logging_config(monkeypatch, caplog, verbose_cfg, debug_cfg, result):
         assert messages == result
 
 
-def test_main_version(monkeypatch, caplog, fake_opts):
+def test_main_version(monkeypatch, capsys, fake_opts):
     fake_opts.options.version = True
     monkeypatch.setattr(optparse, 'OptionParser', fake_opts)
 
-    with pytest.raises(SystemExit) as excinfo:
+    with pytest.raises(SystemExit):
         find_extra_reqs.main()
 
-    assert str(excinfo.value) == __version__
+    assert capsys.readouterr().out == common.version_info() + "\n"
diff --git a/tests/test_find_missing_reqs.py b/tests/test_find_missing_reqs.py
index 559a165..fa75da4 100644
--- a/tests/test_find_missing_reqs.py
+++ b/tests/test_find_missing_reqs.py
@@ -8,7 +8,7 @@ from pathlib import Path
 import pytest
 import pretend
 
-from pip_check_reqs import find_missing_reqs, common, __version__
+from pip_check_reqs import find_missing_reqs, common
 
 
 @pytest.fixture
@@ -178,11 +178,11 @@ def test_logging_config(monkeypatch, caplog, verbose_cfg, debug_cfg, result):
         assert messages == result
 
 
-def test_main_version(monkeypatch, caplog, fake_opts):
+def test_main_version(monkeypatch, capsys, fake_opts):
     fake_opts.options.version = True
     monkeypatch.setattr(optparse, 'OptionParser', fake_opts)
 
-    with pytest.raises(SystemExit) as excinfo:
+    with pytest.raises(SystemExit):
         find_missing_reqs.main()
 
-    assert str(excinfo.value) == __version__
+    assert capsys.readouterr().out == common.version_info() + "\n"