def get_resource_list(self, study, session, experiment, resource_id): """The list of non-dicom resources associated with an experiment returns a list of dicts, mostly interested in ID and name""" logger.debug('Getting resource list for expeiment:{}' .format(experiment)) url = '{}/data/archive/projects/{}' \ '/subjects/{}/experiments/{}' \ '/resources/{}/?format=xml'.format(self.server, study, session, experiment, resource_id) try: result = self._make_xnat_xml_query(url) except: return XnatException("Failed getting resources with url:" .format(url)) if result is None: raise XnatException('Experiment:{} not found for session:{}' ' in study:{}' .format(experiment, session, study)) # define the xml namespace ns = {'cat': 'http://nrg.wustl.edu/catalog'} entries = result.find('cat:entries', ns) if entries is None: # no files found, just a label return None items = [entry.attrib for entry in entries.findall('cat:entry', ns)] return(items)
def get_dicom(self, project, session, experiment, scan, filename=None, retries=3): """Downloads a dicom file from xnat to filename If filename is not specified creates a temporary file and returns the path to that, user needs to be responsible for cleaning up any created tempfiles""" url = '{}/data/archive/projects/{}/' \ 'subjects/{}/experiments/{}/' \ 'scans/{}/resources/DICOM/files?format=zip' \ .format(self.server, project, session, experiment, scan) if not filename: filename = tempfile.mkstemp(prefix="dm2_xnat_extract_") # mkstemp returns a filename and a file object # dealing with the filename in future so close the file object os.close(filename[0]) try: self._get_xnat_stream(url, filename, retries) return(filename) except: try: os.remove(filename[1]) except OSError as e: logger.warning('Failed to delete tempfile:{} with excuse:{}' .format(filename, str(e))) err = XnatException("Failed getting dicom with url:{}".format(url)) err.study = project err.session = session raise err
def get_session(self, study, session, create=False): """Checks to see if session exists in xnat, if create and study doesnt exist will try to create it returns study or none""" logger.debug('Querying for session:{} in study:{}' .format(session, study)) url = '{}/data/archive/projects/{}/subjects/{}?format=json' \ .format(self.server, study, session) try: result = self._make_xnat_query(url) except: raise XnatException("Failed getting session with url:{}" .format(url)) if not result: logger.info('Session:{} not found in study:{}' .format(session, study)) if create: try: self.make_session(study, session) except: raise XnatException("Failed to create session:{} in study:{}" .format(session, study)) result = self.get_session(study, session) return result try: return(result['items'][0]) except (KeyError, ValueError): msg = "Session:{} doesnt exist on xnat for study:{}".format(session, study) logger.info(msg) return XnatException(msg)
def get_resource_ids(self, study, session, experiment, folderName=None, create=True): """ Return a list of resource id's (subfolders) from an experiment """ logger.debug('Getting resource ids for expeiment:{}' .format(experiment)) url = '{}/data/archive/projects/{}' \ '/subjects/{}/experiments/{}' \ '/resources/?format=json'.format(self.server, study, session, experiment) try: result = self._make_xnat_query(url) except: raise XnatException("Failed getting resource ids with url:" .format(url)) if result is None: raise XnatException('Experiment:{} not found for session:{}' ' in study:{}' .format(experiment, session, study)) if create and int(result['ResultSet']['totalRecords']) < 1: return self.create_resource_folder(study, session, experiment, folderName) resource_ids = {} for r in result['ResultSet']['Result']: try: label = r['label'] resource_ids[label] = r['xnat_abstractresource_id'] except KeyError: # some resource folders have no label resource_ids['No Label'] = r['xnat_abstractresource_id'] if not folderName: # foldername not specified return them all resource_id = [val for val in resource_ids.itervalues()] else: # check if folder exists, if not create it try: resource_id = resource_ids[folderName] except KeyError: # folder doesn't exist, create it if not create: return None else: resource_id = self.create_resource_folder(study, session, experiment, folderName) return resource_id
def put_dicoms(self, project, session, experiment, filename, retries=3): """Upload an archive of dicoms to XNAT filename: archive to upload""" headers = {'Content-Type': 'application/zip'} upload_url = "{server}/data/services/import?project={project}" \ "&subject={subject}&session={session}&overwrite=delete" \ "&prearchive=false&inbody=true" upload_url = upload_url.format(server=self.server, project=project, subject=session, session=experiment) try: with open(filename) as data: self._make_xnat_post(upload_url, data, retries, headers) except XnatException as e: e.study = project e.session = session raise e except IOError as e: logger.error('Failed to open file:{} with excuse:' .format(filename, e.strerror)) err = XnatException("Error in file:{}". format(filename)) err.study = project err.session = session raise err except requests.exceptions.RequestException as e: err = XnatException("Error uploading data with url:{}" .format(upload_url)) err.study = project err.session = session raise err
def get_projects(self): """Queries the xnat server for a list of projects""" logger.debug('Querying xnat server for projects') url = '{}/data/archive/projects/?format=json'.format(self.server) try: result = self._make_xnat_query(url) except: raise XnatException("Failed getting projects with url:{}" .format(url)) if not result: raise XnatException("No studies on server:{}" .format(self.server)) return(result['ResultSet']['Result'])
def get_resource_archive(self, project, session, experiment, resource_id, filename=None, retries=3): """Download a resource archive from xnat to filename If filename is not specified creates a temporary file and returns the path to that, user needs to be responsible format cleaning up any created tempfiles""" url = '{}/data/archive/projects/{}/' \ 'subjects/{}/experiments/{}/' \ 'resources/{}/files?format=zip' \ .format(self.server, project, session, experiment, resource_id) if not filename: filename = tempfile.mkstemp(prefix="dm2_xnat_extract_") # mkstemp returns a file object and a filename # we will deal with the filename in future so close the file object os.close(filename[0]) try: self._get_xnat_stream(url, filename, retries) return(filename) except: try: os.remove(filename[1]) except OSError as e: logger.warning('Failed to delete tempfile:{} with excude:{}' .format(filename, str(e))) logger.error('Failed getting resource archive from xnat', exc_info=True) raise XnatException("Failed downloading resource archive with url:{}" .format(url))
def get_project(self, project): logger.debug('Querying xnat server for project:{}'.format(project)) url = '{}/data/archive/projects/{}?format=json'.format(self.server, project) try: result = self._make_xnat_query(url) except: raise XnatException("Failed getting project with url:{}" .format(url)) if not result: logger.warn('Project:{} not found'.format(project)) raise XnatException("Project:{} not found. Are credentials" "exported to the environment and clevis given" "permission on the xnat project?" .format(project)) return(result['items'][0])
def get_sessions(self, study): logger.debug('Querying xnat server for sessions in study' .format(study)) if not self.get_project(study): raise XnatException('Invalid xnat project:' .format(study)) url = '{}/data/archive/projects/{}/subjects/'.format(self.server, study) try: result = self._make_xnat_query(url) except: raise XnatException("Failed getting xnat sessions with url:{}" .format(url)) if not result: raise XnatException('No sessions found for study:{}'.format(study)) return(result['ResultSet']['Result'])
def __init__(self, server, username, password): if server.endswith('/'): server = server[:-1] self.server = server self.auth = (username, password) try: self.get_xnat_session() except Exception as e: logger.warn('Failed getting xnat session') raise XnatException("Failed getting xnat session")
def get_experiment(self, study, session, experiment): logger.debug('Getting experiment:{} for session:{} in study:{}' .format(experiment, session, study)) url = '{}/data/archive/projects/{}' \ '/subjects/{}/experiments/{}' \ '?format=json'.format(self.server, study, session, experiment) try: result = self._make_xnat_query(url) except: raise XnatException("Failed getting experiments with url:{}" .format(url)) if not result: raise XnatException('Experiment:{} not found for session:{}' ' in study:{}' .format(experiment, session, study)) return(result['items'][0])
def get_scan_list(self, study, session, experiment): """The list of dicom scans in an experiment""" url = '{}/data/archive/projects/{}' \ '/subjects/{}/experiments/{}' \ '/scans/?format=json'.format(self.server, study, session, experiment) try: result = self._make_xnat_query(url) except: return XnatException('Failed getting scans with url:{}' .format(url)) if result is None: e = XnatException('Scan not found for experiment:{}' .format(experiment)) e.study = study e.session = session raise e return(result['ResultSet']['Result'])
def put_resource(self, project, session, experiment, filename, data, folder, retries=3): """POST a resource file to the xnat server filename: string to store filename as data: string containing data (such as produced by zipfile.ZipFile.read())""" resource_id = self.get_resource_ids(project, session, experiment, folderName=folder) attach_url = "{server}/data/archive/projects/{project}/" \ "subjects/{subject}/experiments/{experiment}/" \ "resources/{resource_id}/" \ "files/{filename}?inbody=true" uploadname = urllib.quote(filename) url = attach_url.format(server=self.server, project=project, subject=session, experiment=experiment, resource_id=resource_id, filename=uploadname) try: self._make_xnat_post(url, data) except XnatException as err: err.study = project err.session = session raise err except: logger.warning("Failed adding resource to xnat with url:{}" .format(url)) err = XnatException("Failed adding resource to xnat") err.study = project err.session = session
def get_scan_info(self, study, session, experiment, scanid): """Returns info about an xnat scan""" url = '{}/data/archive/projects/{}' \ '/subjects/{}/experiments/{}' \ '/scans/{}/?format=json'.format(self.server, study, session, experiment, scanid) try: result = self._make_xnat_query(url) except: return XnatException('Failed getting scan with url:{}' .format(url)) if result is None: e = XnatException('Scan:{} not found for experiment:{}' .format(scanid, experiment)) e.study = study e.session = session raise e return(result['items'][0])
def _make_xnat_post(self, url, data, retries=3, headers=None): logger.debug('POSTing data to xnat, {} retries left'.format(retries)) response = self.session.post(url, headers=headers, data=data, timeout=60*60) if response.status_code == 401: # possibly the session has timed out logger.info('Session may have expired, resetting') self.get_xnat_session() response = self.session.post(url, headers=headers, data=data) if response.status_code is 504: if retries: logger.warning('xnat server timed out, retrying') time.sleep(30) self._make_xnat_post(url, data, retries=retries - 1) else: logger.warn('xnat server timed out, giving up') response.raise_for_status() elif response.status_code is not 200: if 'multiple imaging sessions.' in response.content: raise XnatException('Multiple imaging sessions in archive,' ' check prearchive') if '502 Bad Gateway' in response.content: raise XnatException('Bad gateway error: Check tomcat logs') if 'Unable to identify experiment' in response.content: raise XnatException('Unable to identify experiment, did dicom upload fail?') else: raise XnatException('An unknown error occured uploading data.' 'Status code:{}, reason:{}' .format(response.status_code, response.content))
def delete_resource(self, project, session, experiment, resource_group_id, resource_id, retries=3): """Delete a resource file from xnat""" url = '{}/data/archive/projects/{}/' \ 'subjects/{}/experiments/{}/' \ 'resources/{}/files/{}'.format(self.server, project, session, experiment, resource_group_id, resource_id) try: self._make_xnat_delete(url) except: raise XnatException('Failed deleting resource with url:{}' .format(url))
def get_experiments(self, study, session): logger.debug('Getting experiments for session:{} in study:{}' .format(session, study)) url = '{}/data/archive/projects/{}' \ '/subjects/{}/experiments/?format=json'.format(self.server, study, session) try: result = self._make_xnat_query(url) except: raise XnatException("Failed getting experiments with url:{}" .format(url)) if not result: logger.warn('No experiments found for session:{} in study:{}' .format(session, study)) return return(result['ResultSet']['Result'])