Repository: kedro-org/kedro

Issue:
KedroSession: getpass.getuser() call fails
## Description
First of all, I want to thank you for this splendid work that is Kedro. I believe it makes our life easier and I am glad that we have adopted it at my company.
This is the first time that I post an issue here, so I hope to frame this correctly!

In my company, we are using Kedro pipelines orchestrated in Airflow (we don't use kedro-airflow but we have a custom setup).
I have recently upgraded one pipeline to Kedro 0.18, but it's currently failing here:

```
# Line 167 of kedro/framework/session/session.py
session_data["username"] = getpass.getuser()
```

with the following error:
``KeyError: 'getpwuid(): uid not found: 1000``

I believe this is due to this process running with an uid that is not defined in /etc/passwd.
I am not super familiar with this things, but googling, it seems this is not an uncommon situation when using existing images.

Maybe it might be better to wrap that line in a try/except clause and catch ImportErrors?
This username tag does not seem to serve a critical purpose so I think the code should not crash because of this.

Right now I have solved it temporarily by setting an environment variable (USERNAME). What do you think?


## Steps to Reproduce
1. Run Kedro pipeline in a containerized setting with a UID that does not exist in /etc/passwd

## Expected Result
I expect that the code runs fine, and maybe the KedroSession is initialized with a "none" user or something like that

## Actual Result
The code crashes with a KeyError when setting username in KedroSession

## Your Environment
Our custom Docker Image is ultimately based on python:3.8-buster:


* Kedro version used (`pip show kedro` or `kedro -V`): 0.18.1
* Python version used (`python -V`): 3.8
* Operating system and version: Code running in Airflow on a custom image based on python:3.8-buster



Discussion:
Hello @naikio and thank you for your comments! Very pleased to hear that kedro makes your life easier 🙂 Do you mind me asking what your company is?

Thanks for the very clear bug report. You're right that that this `username` isn't currently used anywhere, and your current workaround of setting `USERNAME` in an environment variable is definitely a good one.

The username destined to appear on the experiment tracking screen in kedro-viz but doesn't seem to have quite made it there yet (see recently opened https://github.com/kedro-org/kedro-viz/issues/911). I was actually considering adding `getpass.getuser` to our code so I'm very surprised to see that it's already there! Your bug report is remarkably timely 😀 

I'm actually also surprised that that this is the first time we've heard about this problem since this line of code will have been executed A LOT on lots of different machines (it's run every time anyone does a `kedro run`). I'm not a devops person but I would be curious to know if your situation of not having uid defined in `/etc/passwd` is therefore quite unusual or not quite right in some way, even if it's a problem you've seen discussed in other contexts online?

Either way, you're absolutely right that kedro should not crash in such a scenario and we should wrap the call in a `try/except`. If you get a chance please feel free to raise a PR that does this - otherwise I'll add it to our backlog.

Resolving patch:
diff --git a/kedro/framework/session/session.py b/kedro/framework/session/session.py
--- a/kedro/framework/session/session.py
+++ b/kedro/framework/session/session.py
@@ -163,7 +163,12 @@ def create(  # pylint: disable=too-many-arguments
         if extra_params:
             session_data["extra_params"] = extra_params
 
-        session_data["username"] = getpass.getuser()
+        try:
+            session_data["username"] = getpass.getuser()
+        except Exception as exc:  # pylint: disable=broad-except
+            logging.getLogger(__name__).debug(
+                "Unable to get username. Full exception: %s", exc
+            )
 
         session._store.update(session_data)
 


Test patch:
diff --git a/tests/framework/session/test_session.py b/tests/framework/session/test_session.py
--- a/tests/framework/session/test_session.py
+++ b/tests/framework/session/test_session.py
@@ -496,6 +496,28 @@ def test_git_describe_error(
         ]
         assert actual_log_messages == expected_log_messages
 
+    def test_get_username_error(self, fake_project, mock_package_name, mocker, caplog):
+        """Test that username information is not added to the session store
+        if call to getuser() fails
+        """
+        caplog.set_level(logging.DEBUG, logger="kedro")
+
+        mocker.patch("subprocess.check_output")
+        mocker.patch("kedro.framework.session.KedroSession._setup_logging")
+        mocker.patch("getpass.getuser", side_effect=FakeException("getuser error"))
+        session = KedroSession.create(mock_package_name, fake_project)
+        assert "username" not in session.store
+
+        expected_log_messages = [
+            "Unable to get username. Full exception: getuser error"
+        ]
+        actual_log_messages = [
+            rec.getMessage()
+            for rec in caplog.records
+            if rec.name == SESSION_LOGGER_NAME and rec.levelno == logging.DEBUG
+        ]
+        assert actual_log_messages == expected_log_messages
+
     @pytest.mark.usefixtures("mock_settings")
     def test_log_error(self, fake_project, mock_package_name):
         """Test logging the error by the session"""