diff --git a/synapseclient/api/entity_factory.py b/synapseclient/api/entity_factory.py index 04dec79d4..cb5637ced 100644 --- a/synapseclient/api/entity_factory.py +++ b/synapseclient/api/entity_factory.py @@ -412,12 +412,19 @@ def _check_entity_restrictions( if restriction_information and restriction_information.get( "hasUnmetAccessRequirement", None ): - warning_message = ( - "\nThis entity has access restrictions. Please visit the web page for this entity " - f'(syn.onweb("{synapse_id}")). Look for the "Access" label and the lock icon underneath ' - 'the file name. Click "Request Access", and then review and fulfill the file ' - "download requirement(s).\n" - ) + if not syn.credentials or not syn.credentials._token: + warning_message = ( + "You have not provided valid credentials for authentication with Synapse." + " Please provide an authentication token and use `synapseclient.login()` before your next attempt." + " See https://python-docs.synapse.org/tutorials/authentication/ for more information." + ) + else: + warning_message = ( + "\nThis entity has access restrictions. Please visit the web page for this entity " + f'(syn.onweb("{synapse_id}")). Look for the "Access" label and the lock icon underneath ' + 'the file name. Click "Request Access", and then review and fulfill the file ' + "download requirement(s).\n" + ) if download_file and bundle.get("entityType") not in ("project", "folder"): raise SynapseUnmetAccessRestrictions(warning_message) - syn.logger.warn(warning_message) + syn.logger.warning(warning_message) diff --git a/synapseclient/client.py b/synapseclient/client.py index fb42a470b..1e193d23d 100644 --- a/synapseclient/client.py +++ b/synapseclient/client.py @@ -1445,17 +1445,26 @@ def _check_entity_restrictions( Raises: SynapseUnmetAccessRestrictions: Warning for unmet access requirements. """ - restrictionInformation = bundle["restrictionInformation"] - if restrictionInformation["hasUnmetAccessRequirement"]: - warning_message = ( - "\nThis entity has access restrictions. Please visit the web page for this entity " - f'(syn.onweb("{id_of(entity)}")). Look for the "Access" label and the lock icon underneath ' - 'the file name. Click "Request Access", and then review and fulfill the file ' - "download requirement(s).\n" - ) + restriction_information = bundle.get("restrictionInformation", None) + if restriction_information and restriction_information.get( + "hasUnmetAccessRequirement", None + ): + if not self.credentials or not self.credentials._token: + warning_message = ( + "You have not provided valid credentials for authentication with Synapse." + " Please provide an authentication token and use `synapseclient.login()` before your next attempt." + " See https://python-docs.synapse.org/tutorials/authentication/ for more information." + ) + else: + warning_message = ( + "\nThis entity has access restrictions. Please visit the web page for this entity " + f'(syn.onweb("{id_of(entity)}")). Look for the "Access" label and the lock icon underneath ' + 'the file name. Click "Request Access", and then review and fulfill the file ' + "download requirement(s).\n" + ) if downloadFile and bundle.get("entityType") not in ("project", "folder"): raise SynapseUnmetAccessRestrictions(warning_message) - warnings.warn(warning_message) + self.logger.warning(warning_message) def _getFromFile( self, filepath: str, limitSearch: str = None, md5: str = None diff --git a/synapseclient/core/credentials/cred_data.py b/synapseclient/core/credentials/cred_data.py index c8e65a12e..92352529b 100644 --- a/synapseclient/core/credentials/cred_data.py +++ b/synapseclient/core/credentials/cred_data.py @@ -109,7 +109,8 @@ def secret(self) -> str: return self._token def __call__(self, r): - r.headers.update({"Authorization": f"Bearer {self.secret}"}) + if self.secret: + r.headers.update({"Authorization": f"Bearer {self.secret}"}) return r def __repr__(self): diff --git a/tests/unit/synapseclient/unit_test_client.py b/tests/unit/synapseclient/unit_test_client.py index aefdbe0c3..939103806 100644 --- a/tests/unit/synapseclient/unit_test_client.py +++ b/tests/unit/synapseclient/unit_test_client.py @@ -1157,121 +1157,169 @@ def expected_request_json(token) -> str: ) -def test_check_entity_restrictions_no_unmet_restriction(syn: Synapse) -> None: - with patch("warnings.warn") as mocked_warn: - bundle = { - "entity": { - "id": "syn123", - "name": "anonymous", - "concreteType": "org.sagebionetworks.repo.model.FileEntity", - "parentId": "syn12345", - }, - "restrictionInformation": {"hasUnmetAccessRequirement": False}, - } - entity = "syn123" - syn._check_entity_restrictions(bundle, entity, True) - mocked_warn.assert_not_called() - +class TestCheckEntityRestrictions: + @pytest.fixture(autouse=True, scope="function") + def init_syn(self, syn: Synapse) -> None: + self.syn = syn + self.syn.credentials = SynapseAuthTokenCredentials(token="abc", username="def") -def test_check_entity_restrictions_unmet_restriction_entity_file_with_download_file_is_true( - syn: Synapse, -) -> None: - with patch("warnings.warn") as mocked_warn: - bundle = { - "entity": { - "id": "syn123", - "name": "anonymous", - "concreteType": "org.sagebionetworks.repo.model.FileEntity", - "parentId": "syn12345", - }, - "entityType": "file", - "restrictionInformation": {"hasUnmetAccessRequirement": True}, - } - entity = "syn123" - pytest.raises( - SynapseUnmetAccessRestrictions, - syn._check_entity_restrictions, - bundle, - entity, - True, - ) - mocked_warn.assert_not_called() + def test_check_entity_restrictions_no_unmet_restriction(self) -> None: + with patch("logging.Logger.warning") as mocked_warn: + bundle = { + "entity": { + "id": "syn123", + "name": "anonymous", + "concreteType": "org.sagebionetworks.repo.model.FileEntity", + "parentId": "syn12345", + }, + "restrictionInformation": {"hasUnmetAccessRequirement": False}, + } + entity = "syn123" + self.syn._check_entity_restrictions(bundle, entity, True) + mocked_warn.assert_not_called() + def test_check_entity_restrictions_unmet_restriction_entity_file_with_download_file_is_true( + self, + ) -> None: + with patch("logging.Logger.warning") as mocked_warn: + bundle = { + "entity": { + "id": "syn123", + "name": "anonymous", + "concreteType": "org.sagebionetworks.repo.model.FileEntity", + "parentId": "syn12345", + }, + "entityType": "file", + "restrictionInformation": {"hasUnmetAccessRequirement": True}, + } + entity = "syn123" + pytest.raises( + SynapseUnmetAccessRestrictions, + self.syn._check_entity_restrictions, + bundle, + entity, + True, + ) + mocked_warn.assert_not_called() -def test_check_entity_restrictions_unmet_restriction_entity_project_with_download_file_is_true( - syn: Synapse, -) -> None: - with patch("warnings.warn") as mocked_warn: - bundle = { - "entity": { - "id": "syn123", - "name": "anonymous", - "concreteType": "org.sagebionetworks.repo.model.FileEntity", - "parentId": "syn12345", - }, - "entityType": "project", - "restrictionInformation": {"hasUnmetAccessRequirement": True}, - } - entity = "syn123" - syn._check_entity_restrictions(bundle, entity, True) - mocked_warn.assert_called_with( - "\nThis entity has access restrictions. Please visit the web page for this entity " - '(syn.onweb("syn123")). Look for the "Access" label and the lock icon underneath ' - 'the file name. Click "Request Access", and then review and fulfill the file ' - "download requirement(s).\n" - ) + def test_check_entity_restrictions_unmet_restriction_entity_project_with_download_file_is_true( + self, + ) -> None: + with patch("logging.Logger.warning") as mocked_warn: + bundle = { + "entity": { + "id": "syn123", + "name": "anonymous", + "concreteType": "org.sagebionetworks.repo.model.FileEntity", + "parentId": "syn12345", + }, + "entityType": "project", + "restrictionInformation": {"hasUnmetAccessRequirement": True}, + } + entity = "syn123" + self.syn._check_entity_restrictions(bundle, entity, True) + mocked_warn.assert_called_with( + "\nThis entity has access restrictions. Please visit the web page for this entity " + '(syn.onweb("syn123")). Look for the "Access" label and the lock icon underneath ' + 'the file name. Click "Request Access", and then review and fulfill the file ' + "download requirement(s).\n" + ) + def test_check_entity_restrictions_unmet_restriction_entity_folder_with_download_file_is_true_and_no_token( + self, + ) -> None: + with patch("logging.Logger.warning") as mocked_warn: + bundle = { + "entity": { + "id": "syn123", + "name": "anonymous", + "concreteType": "org.sagebionetworks.repo.model.FileEntity", + "parentId": "syn12345", + }, + "entityType": "folder", + "restrictionInformation": {"hasUnmetAccessRequirement": True}, + } + entity = "syn123" + self.syn.credentials = SynapseAuthTokenCredentials(token="") + self.syn._check_entity_restrictions(bundle, entity, True) + mocked_warn.assert_called_with( + "You have not provided valid credentials for authentication with Synapse." + " Please provide an authentication token and use `synapseclient.login()` before your next attempt." + " See https://python-docs.synapse.org/tutorials/authentication/ for more information." + ) -def test_check_entity_restrictions_unmet_restriction_entity_folder_with_download_file_is_true( - syn: Synapse, -) -> None: - with patch("warnings.warn") as mocked_warn: - bundle = { - "entity": { - "id": "syn123", - "name": "anonymous", - "concreteType": "org.sagebionetworks.repo.model.FileEntity", - "parentId": "syn12345", - }, - "entityType": "folder", - "restrictionInformation": {"hasUnmetAccessRequirement": True}, - } - entity = "syn123" - syn._check_entity_restrictions(bundle, entity, True) - mocked_warn.assert_called_with( - "\nThis entity has access restrictions. Please visit the web page for this entity " - '(syn.onweb("syn123")). Look for the "Access" label and the lock icon underneath ' - 'the file name. Click "Request Access", and then review and fulfill the file ' - "download requirement(s).\n" - ) + def test_check_entity_restrictions_unmet_restriction_entity_folder_with_download_file_is_true_and_no_credentials( + self, + ) -> None: + with patch("logging.Logger.warning") as mocked_warn: + bundle = { + "entity": { + "id": "syn123", + "name": "anonymous", + "concreteType": "org.sagebionetworks.repo.model.FileEntity", + "parentId": "syn12345", + }, + "entityType": "folder", + "restrictionInformation": {"hasUnmetAccessRequirement": True}, + } + entity = "syn123" + self.syn.credentials = None + self.syn._check_entity_restrictions(bundle, entity, True) + mocked_warn.assert_called_with( + "You have not provided valid credentials for authentication with Synapse." + " Please provide an authentication token and use `synapseclient.login()` before your next attempt." + " See https://python-docs.synapse.org/tutorials/authentication/ for more information." + ) + def test_check_entity_restrictions_unmet_restriction_entity_folder_with_download_file_is_true( + self, + ) -> None: + with patch("logging.Logger.warning") as mocked_warn: + bundle = { + "entity": { + "id": "syn123", + "name": "anonymous", + "concreteType": "org.sagebionetworks.repo.model.FileEntity", + "parentId": "syn12345", + }, + "entityType": "folder", + "restrictionInformation": {"hasUnmetAccessRequirement": True}, + } + entity = "syn123" + self.syn._check_entity_restrictions(bundle, entity, True) + mocked_warn.assert_called_with( + "\nThis entity has access restrictions. Please visit the web page for this entity " + '(syn.onweb("syn123")). Look for the "Access" label and the lock icon underneath ' + 'the file name. Click "Request Access", and then review and fulfill the file ' + "download requirement(s).\n" + ) -def test_check_entity_restrictions__unmet_restriction_downloadFile_is_False( - syn: Synapse, -) -> None: - with patch("warnings.warn") as mocked_warn: - bundle = { - "entity": { - "id": "syn123", - "name": "anonymous", - "concreteType": "org.sagebionetworks.repo.model.FileEntity", - "parentId": "syn12345", - }, - "entityType": "file", - "restrictionInformation": {"hasUnmetAccessRequirement": True}, - } - entity = "syn123" + def test_check_entity_restrictions__unmet_restriction_downloadFile_is_False( + self, + ) -> None: + with patch("logging.Logger.warning") as mocked_warn: + bundle = { + "entity": { + "id": "syn123", + "name": "anonymous", + "concreteType": "org.sagebionetworks.repo.model.FileEntity", + "parentId": "syn12345", + }, + "entityType": "file", + "restrictionInformation": {"hasUnmetAccessRequirement": True}, + } + entity = "syn123" - syn._check_entity_restrictions(bundle, entity, False) - mocked_warn.assert_called_once() + self.syn._check_entity_restrictions(bundle, entity, False) + mocked_warn.assert_called_once() - bundle["entityType"] = "project" - syn._check_entity_restrictions(bundle, entity, False) - assert mocked_warn.call_count == 2 + bundle["entityType"] = "project" + self.syn._check_entity_restrictions(bundle, entity, False) + assert mocked_warn.call_count == 2 - bundle["entityType"] = "folder" - syn._check_entity_restrictions(bundle, entity, False) - assert mocked_warn.call_count == 3 + bundle["entityType"] = "folder" + self.syn._check_entity_restrictions(bundle, entity, False) + assert mocked_warn.call_count == 3 class TestGetColumns(object): @@ -1299,6 +1347,7 @@ class TestPrivateGetEntityBundle: @pytest.fixture(autouse=True, scope="function") def init_syn(self, syn: Synapse) -> None: self.syn = syn + self.syn.credentials = SynapseAuthTokenCredentials(token="abc", username="def") @pytest.fixture(scope="function", autouse=True) def setup_method(self) -> None: