diff --git a/pythonanywhere/files.py b/pythonanywhere/files.py index 1c8652a..a5ddfb3 100644 --- a/pythonanywhere/files.py +++ b/pythonanywhere/files.py @@ -39,6 +39,14 @@ def contents(self): logger.warning(snakesay(str(e))) return None + @property + def tree(self): + try: + return self.api.tree_get(self.path) + except Exception as e: + logger.warning(snakesay(str(e))) + return None + def delete(self): try: self.api.path_delete(self.path) @@ -90,11 +98,7 @@ def unshare(self): if result == 204: logger.info(snakesay(f"{self.path} is no longer shared!")) return True - logger.info(snakesay(f"Could not unshare {self.path}... :(")) + logger.warning(snakesay(f"Could not unshare {self.path}... :(")) return False logger.info(snakesay(f"{self.path} is not being shared, no need to stop sharing...")) return True - - def tree(self): - pass - diff --git a/pythonanywhere/files.pyi b/pythonanywhere/files.pyi index 58932a3..e915ebd 100644 --- a/pythonanywhere/files.pyi +++ b/pythonanywhere/files.pyi @@ -5,7 +5,8 @@ from typing_extensions import Literal class PAPath: def __init__(self, path: str) -> None: ... def __repr__(self) -> str: ... - def contents(self) -> Union[dict, str]: ... + def contents(self) -> Optional[Union[dict, str]]: ... + def tree(self) -> Optional[list]: ... def delete(self) -> bool: ... def upload(self, content: bytes) -> bool: ... def get_sharing_url(self) -> str: ... diff --git a/tests/test_api_files.py b/tests/test_api_files.py index 7926b47..718d4b1 100644 --- a/tests/test_api_files.py +++ b/tests/test_api_files.py @@ -336,7 +336,6 @@ def test_raises_when_path_not_pointing_to_directory(self, api_token, api_respons expected_error_msg = ( f"GET to {url} failed, got : {invalid_path} is not a directory" ) - print(e.value) assert str(e.value) == expected_error_msg def test_raises_when_path_does_not_exist(self, api_token, api_responses): @@ -356,5 +355,4 @@ def test_raises_when_path_does_not_exist(self, api_token, api_responses): expected_error_msg = ( f"GET to {url} failed, got : {invalid_path} does not exist" ) - print(e.value) assert str(e.value) == expected_error_msg diff --git a/tests/test_files.py b/tests/test_files.py index 1aca7ba..d61c1e4 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -73,7 +73,35 @@ def test_warns_when_path_unavailable(self, mocker): @pytest.mark.files -class TestPAPathDelete(TestFiles): +class TestPAPathTree(): + def test_returns_list_of_regular_dirs_and_files(self, mocker): + mock_tree_get = mocker.patch("pythonanywhere.api.files_api.Files.tree_get") + path = "/home/user" + tree = [f"{path}/README.txt"] + mock_tree_get.return_value = tree + + result = PAPath(path).tree + + assert result == tree + assert mock_tree_get.call_args == call(path) + + def test_warns_if_fetching_of_tree_unsuccessful(self, mocker): + mock_tree_get = mocker.patch("pythonanywhere.api.files_api.Files.tree_get") + mock_tree_get.side_effect = Exception("failed") + mock_snake = mocker.patch("pythonanywhere.files.snakesay") + mock_warning = mocker.patch("pythonanywhere.files.logger.warning") + path = "/home/another_user" + + result = PAPath(path).tree + + assert result is None + assert mock_tree_get.call_args == call(path) + assert mock_snake.call_args == call("failed") + assert mock_warning.call_args == call(mock_snake.return_value) + + +@pytest.mark.files +class TestPAPathDelete(): def test_informes_about_successful_file_deletion(self, mocker): mock_delete = mocker.patch("pythonanywhere.api.files_api.Files.path_delete") mock_delete.return_value.status_code = 204 @@ -100,7 +128,7 @@ def test_warns_about_failed_deletion(self, mocker): @pytest.mark.files -class TestPAPathUpload(TestFiles): +class TestPAPathUpload(): def test_informs_about_successful_upload_of_a_file(self, mocker): mock_post = mocker.patch("pythonanywhere.api.files_api.Files.path_post") mock_post.return_value = 201 @@ -150,7 +178,7 @@ def test_warns_when_file_has_not_been_uploaded(self, mocker): @pytest.mark.files -class TestPAPathShare(TestFiles): +class TestPAPathShare(): def test_returns_full_url_for_shared_file(self, mocker): mock_sharing_get = mocker.patch("pythonanywhere.api.files_api.Files.sharing_get") mock_sharing_get.return_value = "url" @@ -266,7 +294,7 @@ def test_warns_if_unshare_not_successful(self, mocker): mock_sharing_delete = mocker.patch("pythonanywhere.api.files_api.Files.sharing_delete") mock_sharing_delete.return_value = 999 mock_snake = mocker.patch("pythonanywhere.files.snakesay") - mock_info = mocker.patch("pythonanywhere.files.logger.info") + mock_warning = mocker.patch("pythonanywhere.files.logger.warning") path_to_shared_file = "/pa/path/to/a/file" result = PAPath(path_to_shared_file).unshare() @@ -274,5 +302,5 @@ def test_warns_if_unshare_not_successful(self, mocker): assert mock_sharing_get.call_args == call(path_to_shared_file) assert mock_sharing_delete.call_args == call(path_to_shared_file) assert mock_snake.call_args == call(f"Could not unshare {path_to_shared_file}... :(") - assert mock_info.call_args == call(mock_snake.return_value) + assert mock_warning.call_args == call(mock_snake.return_value) assert result == False