Repository: gitpython-developers/GitPython

Issue:
Windows : ImportError: No module named pwd on util.py
When i try to build gitpython on Windows Server i have this error message.

```powershell
File "C:\project\.tox\back\lib\site-packages\git\objects\commit.py", line 318, in create_from_tree
    committer = committer or Actor.committer(cr)
  File "C:\project\.tox\back\lib\site-packages\git\util.py", line 416, in committer
    return cls._main_actor(cls.env_committer_name, cls.env_committer_email, config_reader)
  File "C:\project\.tox\back\lib\site-packages\git\util.py", line 386, in _main_actor
    default_email = get_user_id()
  File "C:\project\.tox\back\lib\site-packages\git\util.py", line 152, in get_user_id
    return "%s@%s" % (getpass.getuser(), platform.node())
  File "c:\python27\Lib\getpass.py", line 157, in getuser
    import pwd
ImportError: No module named pwd
```

After search, the only solution is try [this hack](https://t37.net/on-getting-the-running-process-user-under-python-and-supervisord.html) on [utiy.py](https://github.com/gitpython-developers/GitPython/blob/master/git/util.py#L14) file.

Then use this :  

```python
try:
    import pwd
except ImportError:
    import winpwd as pwd
import os

def get_user_id():
    """:return: string identifying the currently active system user as name@node"""
    return "%s@%s" % (pwd.getpwuid(os.getuid()).pw_name, platform.node())
```

instead of 

```python
import getpass

def get_user_id():
    """:return: string identifying the currently active system user as name@node"""
    return "%s@%s" % (getpass.getuser(), platform.node())
```

What do you think about that ?

Discussion:

Patch:
diff --git a/git/util.py b/git/util.py
index 4f82219e..b81332ea 100644
--- a/git/util.py
+++ b/git/util.py
@@ -705,7 +705,11 @@ class Actor(object):
                 setattr(actor, attr, val)
             except KeyError:
                 if config_reader is not None:
-                    setattr(actor, attr, config_reader.get_value('user', cvar, default()))
+                    try:
+                        val = config_reader.get('user', cvar)
+                    except Exception:
+                        val = default()
+                    setattr(actor, attr, val)
                 # END config-reader handling
                 if not getattr(actor, attr):
                     setattr(actor, attr, default())


Test patch:
diff --git a/test/test_util.py b/test/test_util.py
index ddc5f628..3961ff35 100644
--- a/test/test_util.py
+++ b/test/test_util.py
@@ -22,7 +22,10 @@ from git.objects.util import (
     parse_date,
     tzoffset,
     from_timestamp)
-from test.lib import TestBase
+from test.lib import (
+    TestBase,
+    with_rw_repo,
+)
 from git.util import (
     LockFile,
     BlockingLockFile,
@@ -217,8 +220,23 @@ class TestUtils(TestBase):
             self.assertIsInstance(Actor.author(cr), Actor)
         # END assure config reader is handled
 
+    @with_rw_repo('HEAD')
     @mock.patch("getpass.getuser")
-    def test_actor_get_uid_laziness_not_called(self, mock_get_uid):
+    def test_actor_get_uid_laziness_not_called(self, rwrepo, mock_get_uid):
+        with rwrepo.config_writer() as cw:
+            cw.set_value("user", "name", "John Config Doe")
+            cw.set_value("user", "email", "jcdoe@example.com")
+        
+        cr = rwrepo.config_reader()
+        committer = Actor.committer(cr)
+        author = Actor.author(cr)
+        
+        self.assertEqual(committer.name, 'John Config Doe')
+        self.assertEqual(committer.email, 'jcdoe@example.com')
+        self.assertEqual(author.name, 'John Config Doe')
+        self.assertEqual(author.email, 'jcdoe@example.com')
+        self.assertFalse(mock_get_uid.called)
+            
         env = {
             "GIT_AUTHOR_NAME": "John Doe",
             "GIT_AUTHOR_EMAIL": "jdoe@example.com",
@@ -226,7 +244,7 @@ class TestUtils(TestBase):
             "GIT_COMMITTER_EMAIL": "jane@example.com",
         }
         os.environ.update(env)
-        for cr in (None, self.rorepo.config_reader()):
+        for cr in (None, rwrepo.config_reader()):
             committer = Actor.committer(cr)
             author = Actor.author(cr)
             self.assertEqual(committer.name, 'Jane Doe')
@@ -238,16 +256,16 @@ class TestUtils(TestBase):
     @mock.patch("getpass.getuser")
     def test_actor_get_uid_laziness_called(self, mock_get_uid):
         mock_get_uid.return_value = "user"
-        for cr in (None, self.rorepo.config_reader()):
-            committer = Actor.committer(cr)
-            author = Actor.author(cr)
-            if cr is None:  # otherwise, use value from config_reader
-                self.assertEqual(committer.name, 'user')
-                self.assertTrue(committer.email.startswith('user@'))
-                self.assertEqual(author.name, 'user')
-                self.assertTrue(committer.email.startswith('user@'))
+        committer = Actor.committer(None)
+        author = Actor.author(None)
+        # We can't test with `self.rorepo.config_reader()` here, as the uuid laziness
+        # depends on whether the user running the test has their global user.name config set.
+        self.assertEqual(committer.name, 'user')
+        self.assertTrue(committer.email.startswith('user@'))
+        self.assertEqual(author.name, 'user')
+        self.assertTrue(committer.email.startswith('user@'))
         self.assertTrue(mock_get_uid.called)
-        self.assertEqual(mock_get_uid.call_count, 4)
+        self.assertEqual(mock_get_uid.call_count, 2)
 
     def test_actor_from_string(self):
         self.assertEqual(Actor._from_string("name"), Actor("name", None))