Repository: xarray-contrib/xwrf (language: python)

Issue:
[FEATURE]: Add `xwrf.show_versions()` top level function
### Description

In our bug report form, we ask users to provide the following information 

![Screen Shot 2022-03-01 at 11 47 14 AM](https://user-images.githubusercontent.com/13301940/156230045-307be62c-214a-42ed-981e-9d535d4643e4.png)

It would be useful to have some function in xWRF that inspects a user's environment and reports version information of different dependencies. This information could come in handy when helping troubleshoot issues encountered by users. 



### Implementation

An `xwrf.show_versions()` top-level function that loads a list of dependencies and reports version information for these dependencies. 


### Tests

Running `xwrf.show_versions()` should print the report on the stdout. We could also add a flag (`as_dict=True` or `as_json=True`) to this function to enable returning this information as a dictionary like object with `key='package_name', value='package_version'`

### Questions

- Apart from dependencies listed in `requirements.txt`, which other packages should we include in this report? 


Discussion / hints:

Fix patch:
diff --git a/.github/ISSUE_TEMPLATE/bugreport.yml b/.github/ISSUE_TEMPLATE/bugreport.yml
index 4305fee9..9c06cc70 100644
--- a/.github/ISSUE_TEMPLATE/bugreport.yml
+++ b/.github/ISSUE_TEMPLATE/bugreport.yml
@@ -33,25 +33,15 @@ body:
       label: Relevant log output
       description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for markdown backticks.
       render: python
-  - type: dropdown
-    id: version
+  - type: textarea
+    id: show-versions
     attributes:
-      label: Version
-      description: What version of xwrf are you running?
-      options:
-        - main
+      label: Environment
+      description: |
+        Paste the output of `xwrf.show_versions()` here
+      render: python
     validations:
       required: true
-  - type: dropdown
-    id: python-version
-    attributes:
-      label: Which Python version are you using?
-      multiple: true
-      options:
-        - '3.7'
-        - '3.8'
-        - '3.9'
-        - '3.10'
 
   - type: textarea
     id: extra
diff --git a/xwrf/__init__.py b/xwrf/__init__.py
index b1a05282..93d9acab 100644
--- a/xwrf/__init__.py
+++ b/xwrf/__init__.py
@@ -7,6 +7,7 @@
 from . import postprocess, tutorial
 from .accessors import WRFDataArrayAccessor, WRFDatasetAccessor
 from .config import config
+from .version_report import show_versions
 
 try:
     __version__ = get_distribution(__name__).version
diff --git a/xwrf/version_report.py b/xwrf/version_report.py
new file mode 100644
index 00000000..0b194244
--- /dev/null
+++ b/xwrf/version_report.py
@@ -0,0 +1,105 @@
+from __future__ import annotations
+
+import importlib
+import locale
+import os
+import pathlib
+import platform
+import struct
+import subprocess
+import sys
+
+
+def get_sys_info() -> dict[str, str]:
+    """Returns system information as a dict"""
+
+    # get full commit hash
+    commit = None
+    if pathlib.Path('.git').is_dir() and pathlib.Path('xwrf').is_dir():
+        try:
+            pipe = subprocess.Popen(
+                'git log --format="%H" -n 1'.split(' '),
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+            )
+            so, _ = pipe.communicate()
+        except Exception:
+            pass
+        else:
+            if pipe.returncode == 0:
+                commit = so
+                try:
+                    commit = so.decode('utf-8')
+                except ValueError:
+                    pass
+                commit = commit.strip().strip('"')
+
+    blob = [('xWRF commit', commit)]
+    try:
+        (sysname, _nodename, release, _version, machine, processor) = platform.uname()
+        blob.extend(
+            [
+                ('python', sys.version),
+                ('python-bits', struct.calcsize('P') * 8),
+                ('OS', f'{sysname}'),
+                ('OS-release', f'{release}'),
+                ('machine', f'{machine}'),
+                ('processor', f'{processor}'),
+                ('byteorder', f'{sys.byteorder}'),
+                ('LC_ALL', f'{os.environ.get("LC_ALL", "None")}'),
+                ('LANG', f'{os.environ.get("LANG", "None")}'),
+                ('LOCALE', f'{locale.getlocale()}'),
+            ]
+        )
+    except Exception:
+        pass
+
+    return blob
+
+
+def show_versions(as_dict: bool = False) -> None | dict[str, str]:
+    """Print out versions of xwrf and its dependencies"""
+    packages = [
+        ('xwrf', lambda mod: mod.__version__),
+        ('xarray', lambda mod: mod.__version__),
+        ('numpy', lambda mod: mod.__version__),
+        ('pandas', lambda mod: mod.__version__),
+        ('matplotlib', lambda mod: mod.__version__),
+        ('dask', lambda mod: mod.__version__),
+        ('netCDF4', lambda mod: mod.__version__),
+        ('donfig', lambda mod: mod.__version__),
+        ('xgcm', lambda mod: mod.__version__),
+        ('pyproj', lambda mod: mod.__version__),
+        ('metpy', lambda mod: mod.__version__),
+        ('cf_xarray', lambda mod: mod.__version__),
+        ('pint', lambda mod: mod.__version__),
+        ('pooch', lambda mod: mod.__version__),
+    ]
+
+    packages_blob = {}
+    for (modname, version_func) in packages:
+        try:
+            if modname in sys.modules:
+                mod = sys.modules[modname]
+            else:
+                mod = importlib.import_module(modname)
+        except Exception:
+            packages_blob[modname] = None
+
+        else:
+            try:
+                version = version_func(mod)
+                packages_blob[modname] = version
+            except Exception:
+                packages_blob[modname] = 'installed'
+    sys_info = get_sys_info()
+    packages_info = sorted(packages_blob.items())
+    print('\nSystem Information')
+    print('------------------')
+    print('\n'.join(f'{key:<12}: {value}' for (key, value) in sys_info))
+    print('\nInstalled Python Packages')
+    print('-------------------------')
+    print('\n'.join(f'{modname:<12}: {version}' for (modname, version) in packages_info))
+
+    if as_dict:
+        return {'sys_info': sys_info, 'packages_info': packages_blob}


Test patch:
diff --git a/tests/test_version_report.py b/tests/test_version_report.py
new file mode 100644
index 00000000..e727b82b
--- /dev/null
+++ b/tests/test_version_report.py
@@ -0,0 +1,7 @@
+import xwrf
+
+
+def test_xwrf_version_report():
+    info = xwrf.show_versions(as_dict=True)
+    assert set(info.keys()) == {'sys_info', 'packages_info'}
+    assert info['packages_info']['xwrf'] == xwrf.__version__