def test_post_refreshes_token_when_denied(session: Session): token_refresh_response = refresh_token(datetime(2019, 3, 14, tzinfo=pytz.utc)) with requests_mock.Mocker() as m: m.post('http://citrine-testing.fake/api/v1/tokens/refresh', json=token_refresh_response) m.register_uri('POST', 'http://citrine-testing.fake/api/v1/foo', [ {'status_code': 401, 'json': {'reason': 'invalid-token'}}, {'json': {'foo': 'bar'}} ]) resp = session.post_resource('/foo', json={'data': 'hi'}) assert {'foo': 'bar'} == resp assert datetime(2019, 3, 14) == session.access_token_expiration
def _async_gemd_batch_delete( id_list: List[Union[LinkByUID, UUID, str, BaseEntity]], project_id: UUID, session: Session, dataset_id: Optional[UUID], timeout: float = 2 * 60, polling_delay: float = 1.0) -> List[Tuple[LinkByUID, ApiError]]: """ Shared implementation of Async GEMD Batch deletion. See documentation for _gemd_batch_delete. The only difference is that this version polls for an asynchronous result and can tolerate a very long runtime that the synchronous version cannot. Because this version can tolerate a long runtime, this versions allows for the removal of attribute templates. Parameters ---------- id_list: List[Union[LinkByUID, UUID, str, BaseEntity]] A list of the IDs of data objects to be removed. They can be passed as a LinkByUID tuple, a UUID, a string, or the object itself. A UUID or string is assumed to be a Citrine ID, whereas a LinkByUID or BaseEntity can also be used to provide an external ID. project_id: UUID The Project ID to use in the delete request. session: Session The Citrine session. dataset_id: Optional[UUID] = None An optional dataset ID, which if provided will mandate that all GEMD objects must be within the given dataset. timeout: float Amount of time to wait on the job (in seconds) before giving up. Defaults to 2 minutes. Note that this number has no effect on the underlying job itself, which can also time out server-side. polling_delay: float How long to delay between each polling retry attempt. Returns ------- List[Tuple[LinkByUID, ApiError]] A list of (LinkByUID, api_error) for each failure to delete an object. Note that this method doesn't raise an exception if an object fails to be deleted. """ scoped_uids = [] for uid in id_list: # And now normalize to id/scope pairs if isinstance(uid, BaseEntity): link_by_uid = LinkByUID.from_entity(uid, CITRINE_SCOPE) scoped_uids.append({ 'scope': link_by_uid.scope, 'id': link_by_uid.id }) elif isinstance(uid, LinkByUID): scoped_uids.append({'scope': uid.scope, 'id': uid.id}) elif isinstance(uid, UUID): scoped_uids.append({'scope': 'id', 'id': uid}) elif isinstance(uid, str): try: scoped_uids.append({'scope': 'id', 'id': UUID(uid)}) except ValueError: raise TypeError("{} does not look like a UUID".format(uid)) else: raise TypeError( "id_list must contain only LinkByUIDs, UUIDs, strings, or BaseEntities" ) body = {'ids': scoped_uids} if dataset_id is not None: body.update({'dataset_id': str(dataset_id)}) path = '/projects/{project_id}/gemd/async-batch-delete'.format( **{"project_id": project_id}) response = session.post_resource(path, body) job_id = response["job_id"] return _poll_for_async_batch_delete_result(project_id, session, job_id, timeout, polling_delay)