Repository: sktime/sktime

Issue:
[BUG] `show_versions` is failing with `AttributeError`
I do not have `tensorflow` installed.

```console
❯ 
❯ pip show tensorflow
WARNING: Package(s) not found: tensorflow
❯ 
```

If I run `show_versions`, it's trying to access `__version__` from `tensorflow` and it fails with `AttributeError`, which is not caught.

```pycon
>>> 
>>> from sktime import show_versions
>>> 
>>> show_versions()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/anirban/sktime-fork/sktime/utils/_maint/_show_versions.py", line 112, in show_versions
    deps_info = _get_deps_info(deps=DEFAULT_DEPS_TO_SHOW)
  File "/home/anirban/sktime-fork/sktime/utils/_maint/_show_versions.py", line 88, in _get_deps_info
    ver = get_version(mod)
  File "/home/anirban/sktime-fork/sktime/utils/_maint/_show_versions.py", line 78, in get_version
    return module.__version__
AttributeError: module 'tensorflow' has no attribute '__version__'
>>> 
```

I have `main` installed locally as editable package, and currently on commit e51ec2472a.

---

Possible issue is that line 87 (`mod = importlib.import_module(modname)`) did not throw an error (`ModuleNotFoundError`). I can not explain why.


Discussion:
Could the condition for this bug be that one of many other packages - or perhaps even your local/closed package or environment - adds a `tensorflow` folder?
This is really hard to reproduce, could you perhaps report what `importlib.import_module("tensorflow")` does?
I get this, instead of an error:

```pycon
>>> import importlib
>>> importlib.import_module("tensorflow")
<module 'tensorflow' (<_frozen_importlib_external._NamespaceLoader object at 0x7f16e341f760>)>
```

I do have a non-empty `tensorflow` folder in site-packages. May be from some previous install-uninstall, not sure. Manually removing that does not lead to the error any more.
How odd. An empty folder leads to a different outcome.

This indicates that, in order to make the check safer, we should do sth more general than listening for `ModuleNotFoundError`.

Though, what would that be?
So, for reproducing, the suspected condition is to put a non-empty `tensorflow` folder, with garbage contents, in `site-packags`?
I think a folder in `sys.path`, empty or not-empty.

```pycon
>>> import importlib
>>> import os
>>> 
>>> importlib.import_module("abcdefg")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/anirban/conda-environments/sktime/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1004, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'abcdefg'
>>> 
>>> os.makedirs("abcdefg")
>>> 
>>> importlib.import_module("abcdefg")
<module 'abcdefg' (<_frozen_importlib_external._NamespaceLoader object at 0x7fe6b3b82650>)>
>>> 
```
any suggestions for an elegant catch?
`get_version` function trying to access `__version__` directly without any `get` or `getattr` handling, so we can do `except (ImportError, AttributeError)`. Other than that, I have no narrower suggestion than catching full `Exception`.
hm, I see - I would do this as a second step, not an "instead"

Resolving patch:
diff --git a/sktime/utils/_maint/_show_versions.py b/sktime/utils/_maint/_show_versions.py
--- a/sktime/utils/_maint/_show_versions.py
+++ b/sktime/utils/_maint/_show_versions.py
@@ -75,7 +75,7 @@ def _get_deps_info(deps=None):
         deps = ["sktime"]
 
     def get_version(module):
-        return module.__version__
+        return getattr(module, "__version__", None)
 
     deps_info = {}
 
@@ -85,10 +85,11 @@ def get_version(module):
                 mod = sys.modules[modname]
             else:
                 mod = importlib.import_module(modname)
-            ver = get_version(mod)
-            deps_info[modname] = ver
         except ImportError:
             deps_info[modname] = None
+        else:
+            ver = get_version(mod)
+            deps_info[modname] = ver
 
     return deps_info
 


Test patch:
diff --git a/sktime/utils/_maint/tests/test_show_versions.py b/sktime/utils/_maint/tests/test_show_versions.py
--- a/sktime/utils/_maint/tests/test_show_versions.py
+++ b/sktime/utils/_maint/tests/test_show_versions.py
@@ -1,4 +1,6 @@
 """Tests for the show_versions utility."""
+import pathlib
+import uuid
 
 from sktime.utils._maint._show_versions import (
     DEFAULT_DEPS_TO_SHOW,
@@ -31,3 +33,15 @@ def test_deps_info():
             assert _check_soft_dependencies(f"{key}=={deps_info_default[key]}")
         deps_single_key = _get_deps_info([key])
         assert set(deps_single_key.keys()) == {key}
+
+
+def test_deps_info_deps_missing_package_present_directory():
+    """Test that _get_deps_info does not fail if a dependency is missing."""
+    dummy_package_name = uuid.uuid4().hex
+
+    dummy_folder_path = pathlib.Path(dummy_package_name)
+    dummy_folder_path.mkdir()
+
+    assert _get_deps_info([dummy_package_name]) == {dummy_package_name: None}
+
+    dummy_folder_path.rmdir()