From 768f27018fa1a8e1fe1a22c100eba2610eff69a0 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Thu, 23 May 2019 10:29:09 +0200
Subject: [PATCH] Fix #4: lazy password evaluation

---
 funkwhale_cli/cli.py | 31 ++++++++++++++++++++++++++++++-
 tests/test_cli.py    | 18 ++++++++++++++++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/funkwhale_cli/cli.py b/funkwhale_cli/cli.py
index 12bc25f..fa892e3 100644
--- a/funkwhale_cli/cli.py
+++ b/funkwhale_cli/cli.py
@@ -88,6 +88,35 @@ RAW_DECORATOR = click.option(
     "--raw", is_flag=True, help="Directly output JSON returned by the happy"
 )
 
+class lazy_credential():
+    """
+    A proxy object to request access to the proxy object at the later possible point,
+    cf #4
+    """
+    def __init__(self, *args):
+        self.args = args
+        self._cached_value = None
+
+    @property
+    def value(self):
+        if self._cached_value:
+            return self._cached_value
+        v = keyring.get_password(*self.args)
+        self._cached_value = v
+        return v
+
+    def __str__(self):
+        return str(self.value)
+
+    def __eq__(self, other):
+        return self.value == other
+
+    def __repr__(self):
+        return str(self.value)
+
+    def __bool__(self):
+        return bool(self.value)
+
 
 def set_server(ctx, url, token):
     ctx.ensure_object(dict)
@@ -96,7 +125,7 @@ def set_server(ctx, url, token):
     ctx.obj["SERVER_NETLOC"] = parsed.netloc
     ctx.obj["SERVER_PROTOCOL"] = parsed.scheme
     try:
-        token = token or keyring.get_password(url, "_")
+        token = token or lazy_credential(url, "_")
     except ValueError as e:
         raise click.ClickException("Error while retrieving password from keyring: {}. Your password may be incorrect.".format(e.args[0]))
     except Exception as e:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 4697133..5ba5983 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -1,5 +1,6 @@
 import pytest
 import click
+import keyring
 
 from funkwhale_cli import api
 from funkwhale_cli import cli
@@ -61,3 +62,20 @@ def test_delete_command(group, cli_ctx, session, responses):
 )
 def test_get_pagination_data(input, output):
     assert cli.get_pagination_data(input) == output
+
+
+def test_lazy_credential(mocker):
+    get_password = mocker.patch("keyring.get_password", return_value="password")
+    credential = cli.lazy_credential("http://testurl", "_")
+
+    get_password.assert_not_called()
+
+    str(credential)
+
+    get_password.assert_called_once_with("http://testurl", "_")
+
+    assert credential == "password"
+
+    # result is cached
+    str(credential)
+    assert get_password.call_count == 1
-- 
GitLab