diff --git a/pythonanywhere/files.py b/pythonanywhere/files.py index c525b85..e556ac3 100644 --- a/pythonanywhere/files.py +++ b/pythonanywhere/files.py @@ -3,6 +3,7 @@ providing features for programmatic handling of user's files.""" import logging +from urllib.parse import urljoin from pythonanywhere.api.files_api import Files from pythonanywhere.snakesay import snakesay @@ -22,9 +23,16 @@ def __repr__(self): user_url = self.api.base_url.replace("/api/v0", "") return f"{user_url}{self.path[1:]}" + def _make_pa_url(self, path): + return urljoin(self.api.base_url.split("api")[0], path) + def contents(self): - content = self.api.path_get(self.path) - return content if type(content) == dict else content.decode("utf-8") + try: + content = self.api.path_get(self.path) + return content if type(content) == dict else content.decode("utf-8") + except Exception as e: + logger.warning(snakesay(str(e))) + return None def delete(self): try: @@ -54,8 +62,9 @@ def get_sharing_url(self): url = self.api.sharing_get(self.path) if url: logger.info(snakesay(f"{self.path} is shared at {url}")) - return url - logger.info(snakesay(f"{self.path} has not been shared.")) + return self._make_pa_url(url) + + logger.info(snakesay(f"{self.path} has not been shared")) return "" def share(self): @@ -67,7 +76,7 @@ def share(self): msg = {200: "was already", 201: "successfully"}[code] logger.info(snakesay(f"{self.path} {msg} shared at {shared_url}")) - return shared_url + return self._make_pa_url(shared_url) def unshare(self): already_shared = self.get_sharing_url() diff --git a/tests/test_files.py b/tests/test_files.py index b054319..21778b3 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -5,18 +5,33 @@ import pytest from pythonanywhere.api.base import get_api_endpoint +from pythonanywhere.api.files_api import Files from pythonanywhere.files import PAPath from tests.test_api_files import TestFiles @pytest.mark.files -class TestPAPathRepr(TestFiles): - def test_contains_correct_pythonanywhere_resource_url_for_instantiated_path(self): +class TestPAPathInit(TestFiles): + def test_instantiates_correctly(self, mocker): + pa_path = PAPath('path') + + assert pa_path.path == 'path' + assert type(pa_path.api) == Files + + def test_repr_contains_correct_pythonanywhere_resource_url_for_instantiated_path(self): path = self.home_dir_path user_path = self.base_url.replace('/api/v0', '') assert PAPath(path).__repr__() == f"{user_path}{path[1:]}" + def test_make_pa_url_contains_pa_site_address(self, mocker): + mock_urljoin = mocker.patch("pythonanywhere.files.urljoin") + pa_path = PAPath('path') + + url = pa_path._make_pa_url('rest') + + assert mock_urljoin.call_args == call(pa_path.api.base_url.split("api")[0], 'rest') + @pytest.mark.files class TestPAPathContents(TestFiles): @@ -38,14 +53,17 @@ def test_returns_directory_contents_if_path_points_to_a_directory(self, mocker): assert result == self.default_home_dir_files - def test_raises_when_path_unavailable(self, mocker): + def test_warns_when_path_unavailable(self, mocker): mock_path_get = mocker.patch("pythonanywhere.api.files_api.Files.path_get") mock_path_get.side_effect = Exception("error msg") + mock_snake = mocker.patch("pythonanywhere.files.snakesay") + mock_warning = mocker.patch("pythonanywhere.files.logger.warning") - with pytest.raises(Exception) as e: - PAPath('/home/different_user').contents() + result = PAPath('/home/different_user').contents() - assert str(e.value) == "error msg" + assert mock_snake.call_args == call("error msg") + assert mock_warning.call_args == call(mock_snake.return_value) + assert result is None @pytest.mark.files @@ -127,7 +145,7 @@ def test_warns_when_file_has_not_been_uploaded(self, mocker): @pytest.mark.files class TestPAPathShare(TestFiles): - def test_returns_url_for_shared_file(self, mocker): + 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" mock_snake = mocker.patch("pythonanywhere.files.snakesay") @@ -139,7 +157,7 @@ def test_returns_url_for_shared_file(self, mocker): assert mock_sharing_get.call_args == call(query_path) assert mock_snake.call_args == call(f"{query_path} is shared at url") assert mock_info.call_args == call(mock_snake.return_value) - assert result == "url" + assert result.endswith("url") def test_returns_empty_string_when_file_not_shared(self, mocker): mock_sharing_get = mocker.patch("pythonanywhere.api.files_api.Files.sharing_get") @@ -151,13 +169,14 @@ def test_returns_empty_string_when_file_not_shared(self, mocker): result = PAPath(query_path).get_sharing_url() assert mock_sharing_get.call_args == call(query_path) - assert mock_snake.call_args == call(f"{query_path} has not been shared.") + assert mock_snake.call_args == call(f"{query_path} has not been shared") assert mock_info.call_args == call(mock_snake.return_value) assert result == "" def test_path_already_shared(self, mocker): mock_sharing_post = mocker.patch("pythonanywhere.api.files_api.Files.sharing_post") mock_sharing_post.return_value = (200, "url") + mock_make_url = mocker.patch("pythonanywhere.files.PAPath._make_pa_url") mock_snake = mocker.patch("pythonanywhere.files.snakesay") mock_info = mocker.patch("pythonanywhere.files.logger.info") path_to_share = "/pa/path/to/a/file" @@ -167,11 +186,13 @@ def test_path_already_shared(self, mocker): assert mock_sharing_post.call_args == call(path_to_share) assert mock_snake.call_args == call(f"{path_to_share} was already shared at url") assert mock_info.call_args == call(mock_snake.return_value) - assert result == "url" + assert mock_make_url.call_args == call("url") + assert result == mock_make_url.return_value def test_path_successfully_shared(self, mocker): mock_sharing_post = mocker.patch("pythonanywhere.api.files_api.Files.sharing_post") mock_sharing_post.return_value = (201, "url") + mock_make_url = mocker.patch("pythonanywhere.files.PAPath._make_pa_url") mock_snake = mocker.patch("pythonanywhere.files.snakesay") mock_info = mocker.patch("pythonanywhere.files.logger.info") path_to_share = "/pa/path/to/a/file" @@ -181,7 +202,8 @@ def test_path_successfully_shared(self, mocker): assert mock_sharing_post.call_args == call(path_to_share) assert mock_snake.call_args == call(f"{path_to_share} successfully shared at url") assert mock_info.call_args == call(mock_snake.return_value) - assert result == "url" + assert mock_make_url.call_args == call("url") + assert result == mock_make_url.return_value def test_warns_if_share_fails(self, mocker): mock_sharing_post = mocker.patch("pythonanywhere.api.files_api.Files.sharing_post") @@ -248,4 +270,3 @@ def test_warns_if_unshare_not_successful(self, mocker): 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 result == False -