From 061ca841726ce25595c90dbd3ba70223e1d57eca Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 12:48:56 +0530 Subject: [PATCH 01/11] Add functionality to reset existing token --- evalai/add_token.py | 12 +++++++- evalai/logout.py | 10 ++++++ evalai/main.py | 2 ++ evalai/utils/auth.py | 21 +++++++++++++ tests/test_auth_utils.py | 66 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 evalai/logout.py create mode 100644 tests/test_auth_utils.py diff --git a/evalai/add_token.py b/evalai/add_token.py index cdb9c3abd..bf7d1c1ec 100644 --- a/evalai/add_token.py +++ b/evalai/add_token.py @@ -16,8 +16,18 @@ def set_token(auth_token): Configure EvalAI Token. """ """ - Invoked by `evalai set_token `. + Invoked by `evalai set_token ` or `evalai set_token clear_token`. """ + if auth_token == "clear_token": + reset_user_auth_token() + echo( + style( + "\nAuthentication Token has been reset successfully.\n", + bold=True, + fg="green", + ) + ) + sys.exit() if validators.length(auth_token, min=LEN_OF_TOKEN, max=LEN_OF_TOKEN): if not os.path.exists(AUTH_TOKEN_DIR): os.makedirs(AUTH_TOKEN_DIR) diff --git a/evalai/logout.py b/evalai/logout.py new file mode 100644 index 000000000..81095c53a --- /dev/null +++ b/evalai/logout.py @@ -0,0 +1,10 @@ +import click + +from click import echo, style + +from evalai.utils.auth import reset_user_auth_token + +@click.group(invoke_without_command=True) +def logout(): + reset_user_auth_token() + echo(style("Logout successful", bold=True, fg="green")) diff --git a/evalai/main.py b/evalai/main.py index 34bb252cc..8821f3b3b 100644 --- a/evalai/main.py +++ b/evalai/main.py @@ -9,6 +9,7 @@ from .teams import teams from .get_token import get_token from .login import login +from .logout import logout @click.version_option() @@ -43,3 +44,4 @@ def main(ctx): main.add_command(teams) main.add_command(get_token) main.add_command(login) +main.add_command(logout) diff --git a/evalai/utils/auth.py b/evalai/utils/auth.py index e18f41bbc..6199cc484 100644 --- a/evalai/utils/auth.py +++ b/evalai/utils/auth.py @@ -98,3 +98,24 @@ def get_host_url(): return str(data) except (OSError, IOError) as e: echo(style(e, bold=True, fg="red")) + + +def reset_user_auth_token(): + """ + Resets the auth token of the user by deleting token.json file + """ + if not os.path.exists(AUTH_TOKEN_PATH): + echo( + style( + "\nThe authentication token has not been configured. Please use the commands " + "`evalai login` or `evalai set_token TOKEN` first to set up the configuration.\n", + bold=True, + fg="red", + ), + ) + sys.exit(1) + try: + os.remove(AUTH_TOKEN_PATH) + except (OSError, IOError) as e: + echo(style(e, bold=True, fg="red")) + sys.exit(1) diff --git a/tests/test_auth_utils.py b/tests/test_auth_utils.py new file mode 100644 index 000000000..01cbc33c0 --- /dev/null +++ b/tests/test_auth_utils.py @@ -0,0 +1,66 @@ +import json +import os +import shutil +import tempfile + +from io import StringIO +from unittest import mock +from unittest import TestCase + +from evalai.utils.auth import reset_user_auth_token + +class TestResetUserAuthToken(TestCase): + def setUp(self): + self.base_temp_dir = tempfile.mkdtemp() + self.token_dir = os.path.join(self.base_temp_dir, ".evalai") + self.token_path = os.path.join(self.token_dir, "token.json") + + self.token = "".join(random.choice(string.ascii_lowercase) for _ in range(40)) + self.token_json = json.dumps({"token": self.token}) + + os.makedirs(self.token_dir) + with open(self.token_path, "w") as fw: + fw.write(self.token_json) + + self.patcher = mock.patch("evalai.utils.auth.AUTH_TOKEN_PATH", self.token_path) + self.patcher.start() + + def tearDown(self): + self.patcher.stop() + if os.path.exists(self.base_temp_dir): + shutil.rmtree(self.base_temp_dir) + + def test_reset_user_auth_token_success(self): + self.assertTrue(os.path.exists(self.token_path)) # Make sure the path exists already + reset_user_auth_token() + + self.assertFalse(os.path.exists(self.token_path)) + self.assertEqual(value, expected) + + def test_reset_user_auth_token_when_token_is_not_configured(self): + os.remove(self.token_path) + expected = ("The authentication token has not been configured. Please use the commands ", + "`evalai login` or `evalai set_token TOKEN` first to set up the configuration.") + + with mock.patch("sys.stdout", StringIO()) as fake_out: + with self.assertRaises(SystemExit) as cm: + reset_user_auth_token() + exit_code = cm.exception.error_code + value = fake_out.getvalue().strip() + + self.assertEqual(exit_code, 1) + self.assertEqual(value, expected) + + @mock.patch("evalai.utils.auth.os.remove") + def test_reset_user_auth_token_when_writing_to_file_fails(self, mock_remove): + error = "ExampleError: Example Error Description" + mock_remove.side_effect = OSError(error) + + with mock.patch("sys.stdout", StringIO()) as fake_out: + with self.assertRaises(SystemExit) as cm: + reset_user_auth_token() + exit_code = cm.exception.error_code + value = fake_out.getvalue() + + self.assertEqual(exit_code, 1) + self.assertEqual(value, error) From 5d5139e19051bffe8ebdbc4a18ff36f6448de4f7 Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 12:56:09 +0530 Subject: [PATCH 02/11] Fix flake8 errors --- evalai/add_token.py | 2 ++ evalai/logout.py | 1 + tests/test_auth_utils.py | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/evalai/add_token.py b/evalai/add_token.py index bf7d1c1ec..e3bc115f0 100644 --- a/evalai/add_token.py +++ b/evalai/add_token.py @@ -1,4 +1,5 @@ import os +import sys import click import json @@ -6,6 +7,7 @@ from click import echo, style +from evalai.utils.auth import reset_user_auth_token from evalai.utils.config import AUTH_TOKEN_DIR, AUTH_TOKEN_PATH, LEN_OF_TOKEN diff --git a/evalai/logout.py b/evalai/logout.py index 81095c53a..c768ed110 100644 --- a/evalai/logout.py +++ b/evalai/logout.py @@ -4,6 +4,7 @@ from evalai.utils.auth import reset_user_auth_token + @click.group(invoke_without_command=True) def logout(): reset_user_auth_token() diff --git a/tests/test_auth_utils.py b/tests/test_auth_utils.py index 01cbc33c0..33a698abe 100644 --- a/tests/test_auth_utils.py +++ b/tests/test_auth_utils.py @@ -1,6 +1,8 @@ import json import os +import random import shutil +import string import tempfile from io import StringIO @@ -9,6 +11,7 @@ from evalai.utils.auth import reset_user_auth_token + class TestResetUserAuthToken(TestCase): def setUp(self): self.base_temp_dir = tempfile.mkdtemp() @@ -35,12 +38,11 @@ def test_reset_user_auth_token_success(self): reset_user_auth_token() self.assertFalse(os.path.exists(self.token_path)) - self.assertEqual(value, expected) def test_reset_user_auth_token_when_token_is_not_configured(self): os.remove(self.token_path) expected = ("The authentication token has not been configured. Please use the commands ", - "`evalai login` or `evalai set_token TOKEN` first to set up the configuration.") + "`evalai login` or `evalai set_token TOKEN` first to set up the configuration.") with mock.patch("sys.stdout", StringIO()) as fake_out: with self.assertRaises(SystemExit) as cm: From eae955a49559894441c0abe860e7a863ae257792 Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 13:25:43 +0530 Subject: [PATCH 03/11] Fix click syntax --- evalai/utils/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evalai/utils/auth.py b/evalai/utils/auth.py index 6199cc484..369b8de2d 100644 --- a/evalai/utils/auth.py +++ b/evalai/utils/auth.py @@ -117,5 +117,5 @@ def reset_user_auth_token(): try: os.remove(AUTH_TOKEN_PATH) except (OSError, IOError) as e: - echo(style(e, bold=True, fg="red")) + echo(e) sys.exit(1) From 346faf64ac3554ff0c4aa525367194e50297754c Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 13:32:06 +0530 Subject: [PATCH 04/11] Minor fixes --- tests/test_auth_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_auth_utils.py b/tests/test_auth_utils.py index 33a698abe..cc7efc045 100644 --- a/tests/test_auth_utils.py +++ b/tests/test_auth_utils.py @@ -47,7 +47,7 @@ def test_reset_user_auth_token_when_token_is_not_configured(self): with mock.patch("sys.stdout", StringIO()) as fake_out: with self.assertRaises(SystemExit) as cm: reset_user_auth_token() - exit_code = cm.exception.error_code + exit_code = cm.exception.error_code value = fake_out.getvalue().strip() self.assertEqual(exit_code, 1) From 3c1f95d1cb4cec7bd7f10f902682b7094625e664 Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 13:37:22 +0530 Subject: [PATCH 05/11] Fix testcase issues --- tests/test_auth_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_auth_utils.py b/tests/test_auth_utils.py index cc7efc045..149e7f57c 100644 --- a/tests/test_auth_utils.py +++ b/tests/test_auth_utils.py @@ -47,7 +47,7 @@ def test_reset_user_auth_token_when_token_is_not_configured(self): with mock.patch("sys.stdout", StringIO()) as fake_out: with self.assertRaises(SystemExit) as cm: reset_user_auth_token() - exit_code = cm.exception.error_code + exit_code = cm.exception.code value = fake_out.getvalue().strip() self.assertEqual(exit_code, 1) @@ -61,7 +61,7 @@ def test_reset_user_auth_token_when_writing_to_file_fails(self, mock_remove): with mock.patch("sys.stdout", StringIO()) as fake_out: with self.assertRaises(SystemExit) as cm: reset_user_auth_token() - exit_code = cm.exception.error_code + exit_code = cm.exception.code value = fake_out.getvalue() self.assertEqual(exit_code, 1) From df17a5ebb4fdea46e88e2cf742d87d8cbb94dfae Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 13:49:05 +0530 Subject: [PATCH 06/11] Use three double quotes for multi-line strings --- evalai/utils/auth.py | 4 ++-- tests/test_auth_utils.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evalai/utils/auth.py b/evalai/utils/auth.py index 369b8de2d..77ac79329 100644 --- a/evalai/utils/auth.py +++ b/evalai/utils/auth.py @@ -107,8 +107,8 @@ def reset_user_auth_token(): if not os.path.exists(AUTH_TOKEN_PATH): echo( style( - "\nThe authentication token has not been configured. Please use the commands " - "`evalai login` or `evalai set_token TOKEN` first to set up the configuration.\n", + """\nThe authentication token has not been configured. Please use the commands + `evalai login` or `evalai set_token TOKEN` first to set up the configuration.\n""", bold=True, fg="red", ), diff --git a/tests/test_auth_utils.py b/tests/test_auth_utils.py index 149e7f57c..ee5b91f73 100644 --- a/tests/test_auth_utils.py +++ b/tests/test_auth_utils.py @@ -41,8 +41,8 @@ def test_reset_user_auth_token_success(self): def test_reset_user_auth_token_when_token_is_not_configured(self): os.remove(self.token_path) - expected = ("The authentication token has not been configured. Please use the commands ", - "`evalai login` or `evalai set_token TOKEN` first to set up the configuration.") + expected = """The authentication token has not been configured. Please use the commands + `evalai login` or `evalai set_token TOKEN` first to set up the configuration.""" with mock.patch("sys.stdout", StringIO()) as fake_out: with self.assertRaises(SystemExit) as cm: @@ -62,7 +62,7 @@ def test_reset_user_auth_token_when_writing_to_file_fails(self, mock_remove): with self.assertRaises(SystemExit) as cm: reset_user_auth_token() exit_code = cm.exception.code - value = fake_out.getvalue() + value = fake_out.getvalue().strip() self.assertEqual(exit_code, 1) self.assertEqual(value, error) From 84dcf590c5f4205e593b369ffc0f57cdd7d02266 Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 13:56:07 +0530 Subject: [PATCH 07/11] Revert last change, update multi-line string syntax --- evalai/utils/auth.py | 4 ++-- tests/test_auth_utils.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/evalai/utils/auth.py b/evalai/utils/auth.py index 77ac79329..369b8de2d 100644 --- a/evalai/utils/auth.py +++ b/evalai/utils/auth.py @@ -107,8 +107,8 @@ def reset_user_auth_token(): if not os.path.exists(AUTH_TOKEN_PATH): echo( style( - """\nThe authentication token has not been configured. Please use the commands - `evalai login` or `evalai set_token TOKEN` first to set up the configuration.\n""", + "\nThe authentication token has not been configured. Please use the commands " + "`evalai login` or `evalai set_token TOKEN` first to set up the configuration.\n", bold=True, fg="red", ), diff --git a/tests/test_auth_utils.py b/tests/test_auth_utils.py index ee5b91f73..8c337add2 100644 --- a/tests/test_auth_utils.py +++ b/tests/test_auth_utils.py @@ -41,8 +41,10 @@ def test_reset_user_auth_token_success(self): def test_reset_user_auth_token_when_token_is_not_configured(self): os.remove(self.token_path) - expected = """The authentication token has not been configured. Please use the commands - `evalai login` or `evalai set_token TOKEN` first to set up the configuration.""" + expected = str( + "The authentication token has not been configured. Please use the commands " + "`evalai login` or `evalai set_token TOKEN` first to set up the configuration." + ) with mock.patch("sys.stdout", StringIO()) as fake_out: with self.assertRaises(SystemExit) as cm: From b704f20da166da8c3e6513e5bf92c2dc3409b362 Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 14:07:00 +0530 Subject: [PATCH 08/11] Add docstring for logout command --- evalai/logout.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/evalai/logout.py b/evalai/logout.py index c768ed110..3eeeda7be 100644 --- a/evalai/logout.py +++ b/evalai/logout.py @@ -7,5 +7,11 @@ @click.group(invoke_without_command=True) def logout(): + """ + Log out the user by resetting authentication token + """ + """ + Invoked by `evalai logout` + """ reset_user_auth_token() echo(style("Logout successful", bold=True, fg="green")) From 013a8b261fc5ec81a844345e2b7c5e554c6cdfe9 Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 20:33:23 +0530 Subject: [PATCH 09/11] Remove option to clear token from set_token command --- evalai/add_token.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/evalai/add_token.py b/evalai/add_token.py index e3bc115f0..cdb9c3abd 100644 --- a/evalai/add_token.py +++ b/evalai/add_token.py @@ -1,5 +1,4 @@ import os -import sys import click import json @@ -7,7 +6,6 @@ from click import echo, style -from evalai.utils.auth import reset_user_auth_token from evalai.utils.config import AUTH_TOKEN_DIR, AUTH_TOKEN_PATH, LEN_OF_TOKEN @@ -18,18 +16,8 @@ def set_token(auth_token): Configure EvalAI Token. """ """ - Invoked by `evalai set_token ` or `evalai set_token clear_token`. + Invoked by `evalai set_token `. """ - if auth_token == "clear_token": - reset_user_auth_token() - echo( - style( - "\nAuthentication Token has been reset successfully.\n", - bold=True, - fg="green", - ) - ) - sys.exit() if validators.length(auth_token, min=LEN_OF_TOKEN, max=LEN_OF_TOKEN): if not os.path.exists(AUTH_TOKEN_DIR): os.makedirs(AUTH_TOKEN_DIR) From 45cebc9286ce203d97935b17af08e3417f39adae Mon Sep 17 00:00:00 2001 From: nikochiko Date: Sat, 28 Dec 2019 14:07:00 +0530 Subject: [PATCH 10/11] Add docstring for logout command --- evalai/logout.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/evalai/logout.py b/evalai/logout.py index c768ed110..3eeeda7be 100644 --- a/evalai/logout.py +++ b/evalai/logout.py @@ -7,5 +7,11 @@ @click.group(invoke_without_command=True) def logout(): + """ + Log out the user by resetting authentication token + """ + """ + Invoked by `evalai logout` + """ reset_user_auth_token() echo(style("Logout successful", bold=True, fg="green")) From a36dbf6f0c645cb4bf790c31717b328a2aa92cdd Mon Sep 17 00:00:00 2001 From: Kaustubh Maske Patil <37668193+nikochiko@users.noreply.github.com> Date: Thu, 9 Jan 2020 20:17:05 +0530 Subject: [PATCH 11/11] Clarify unit test name test_reset_user_auth_token_when_writing_to_file_fails -> test_reset_user_auth_token_when_token_file_removal_fails --- tests/test_auth_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_auth_utils.py b/tests/test_auth_utils.py index 8c337add2..4eca378dd 100644 --- a/tests/test_auth_utils.py +++ b/tests/test_auth_utils.py @@ -56,7 +56,7 @@ def test_reset_user_auth_token_when_token_is_not_configured(self): self.assertEqual(value, expected) @mock.patch("evalai.utils.auth.os.remove") - def test_reset_user_auth_token_when_writing_to_file_fails(self, mock_remove): + def test_reset_user_auth_token_when_token_file_removal_fails(self, mock_remove): error = "ExampleError: Example Error Description" mock_remove.side_effect = OSError(error)