Ejemplo n.º 1
0
    def check_send_dicom(self):

        ts = [
            ExplicitVRLittleEndian, ImplicitVRLittleEndian, ExplicitVRBigEndian
        ]

        # create application entity with Find and Move SOP classes as SCU and
        # Storage SOP class as SCP
        MyAE = AE("DCMTK", 9999, [
            PatientRootFindSOPClass, PatientRootMoveSOPClass,
            VerificationSOPClass
        ], [StorageSOPClass], ts)
        MyAE.OnAssociateResponse = OnAssociateResponse
        MyAE.OnAssociateRequest = OnAssociateRequest
        MyAE.OnReceiveStore = OnReceiveStore
        MyAE.start()

        # remote application entity
        PrismaAE = dict(Address="134.157.205.1", Port=104, AET="AN_MRC35181")

        # create association with remote AE
        self.log.info("Request association on PRISMA")

        assoc = MyAE.RequestAssociation(PrismaAE)

        # perform a DICOM ECHO
        st = assoc.VerificationSOPClass.SCU(1)
        self.log.info('DICOM Echo done with status "%s"', st)

        try:
            self.check_send_dicom_from_remoteAE(assoc)
        except Exception as e:
            self.log.warning('CODE ERROR because of %s', e)

        assoc.Release(0)

        # AGAIN with VERIO
        VerioAE = dict(Address="134.157.205.51", Port=104, AET="MRC40527")

        # create association with remote AE
        self.log.info("Request association on VERIO")

        assoc = MyAE.RequestAssociation(VerioAE)

        # perform a DICOM ECHO
        st = assoc.VerificationSOPClass.SCU(1)
        self.log.info('DICOM Echo done with status "%s"', st)

        #try :
        self.check_send_dicom_from_remoteAE(assoc)
        #except Exception as e:
        #    self.log.warning('CODE ERROR because of %s',e)

        assoc.Release(0)

        MyAE.Quit()
Ejemplo n.º 2
0
def dcm_ser_level_find(aet, node, port, laet, patid, studyuid):
    ''' Use pynetdicom to perform a series level query. The result is a list
        of SeriesLevelFields records.
    '''
    global msg_id
    msg_id += 1

    # Create application entity and association with remote AE (port number of 0 to stop it putting up a listen)
    ae = AE(laet, port=0, SOPSCU=[PatientRootFindSOPClass], SOPSCP=[])
    ae.start()
    assoc = ae.RequestAssociation({'Address': node, 'Port': port, 'AET': aet})

    # Query object
    d = Dataset()
    d.PatientID = patid
    d.StudyInstanceUID = studyuid
    d.SeriesInstanceUID = ''
    d.Modality = ''
    d.SeriesDate = ''
    d.SeriesNumber = ''
    d.SeriesDescription = ''
    d.BodyPartExamined = ''
    d.NumberOfSeriesRelatedInstances = ''
    d.QueryRetrieveLevel = 'SERIES'

    # Request returns a generator
    responses = []
    matches = assoc.PatientRootFindSOPClass.SCU(d, msg_id)
    for state, ds in matches:
        if state == 'Pending':
            patid = ds.PatientID if 'PatientID' in ds else ''
            studyuid = ds.StudyInstanceUID if 'StudyInstanceUID' in ds else ''
            seriesuid = ds.SeriesInstanceUID if 'SeriesInstanceUID' in ds else ''
            seriesdate = ds.SeriesDate if 'SeriesDate' in ds else ''
            seriesdescr = ds.SeriesDescription if 'SeriesDescription' in ds else ''
            seriesnumber = ds.SeriesNumber if 'SeriesNumber' in ds else ''
            modality = ds.Modality if 'Modality' in ds else ''
            bodypart = ds.BodyPartExamined if 'BodyPartExamined' in ds else ''
            nimages = ds.NumberOfSeriesRelatedInstances if 'NumberOfSeriesRelatedInstances' in ds else 0
            responses.append(
                SeriesLevelFields(modality, seriesnumber, seriesuid,
                                  seriesdescr, bodypart, nimages))

    assoc.Release(0)
    ae.Quit()

    return responses
Ejemplo n.º 3
0
def dcm_stu_level_find(aet, node, port, laet, patid):
    ''' Use pynetdicom to perform a study level query. The result is a list
        of StudyLevelFields records.
    '''
    global msg_id
    msg_id += 1

    # Create application entity and association with remote AE (port number of 0 to stop it putting up a listen)
    ae = AE(laet, port=0, SOPSCU=[PatientRootFindSOPClass], SOPSCP=[])
    ae.start()
    assoc = ae.RequestAssociation({'Address': node, 'Port': port, 'AET': aet})

    # Query object
    d = Dataset()
    d.PatientID = patid
    d.StudyInstanceUID = ''
    d.StudyID = ''
    d.StudyDate = ''
    d.StudyDescription = ''
    d.NumberOfStudyRelatedSeries = ''
    d.QueryRetrieveLevel = 'STUDY'

    # Request returns a generator
    responses = []
    matches = assoc.PatientRootFindSOPClass.SCU(d, msg_id)
    for state, ds in matches:
        if state == 'Pending':
            patid = ds.PatientID if 'PatientID' in ds else ''
            studyid = ds.StudyID if 'StudyID' in ds else ''
            studyuid = ds.StudyInstanceUID if 'StudyInstanceUID' in ds else ''
            studydate = ds.StudyDate if 'StudyDate' in ds else ''
            studydescr = ds.StudyDescription if 'StudyDescription' in ds else ''
            nseries = ds.NumberOfStudyRelatedSeries if 'NumberOfStudyRelatedSeries' in ds else 0
            responses.append(
                StudyLevelFields(studyid, studyuid, studydate, studydescr,
                                 nseries))

    assoc.Release(0)
    ae.Quit()

    return responses
Ejemplo n.º 4
0
def dcm_pat_level_find(aet, node, port, laet, query_map):
    ''' Use pynetdicom to perform a patient level query. The result is a list
        of PatientLevelFields records.
    '''
    global msg_id
    msg_id += 1

    # Create application entity and association with remote AE (port number of 0 to stop it putting up a listen)
    ae = AE(laet, port=0, SOPSCU=[PatientRootFindSOPClass], SOPSCP=[])
    ae.start()
    assoc = ae.RequestAssociation({'Address': node, 'Port': port, 'AET': aet})

    # Query object
    d = Dataset()
    d.PatientID = patid
    d.PatientName = patname
    d.PatientBirthDate = birthdate
    d.PatientSex = sex
    d.NumberOfPatientRelatedStudies = ''
    d.QueryRetrieveLevel = 'PATIENT'

    # Request returns a generator
    responses = []
    matches = assoc.PatientRootFindSOPClass.SCU(d, msg_id)

    for state, ds in matches:
        if state == 'Pending':
            patname = ds.PatientName if 'PatientName' in ds else 'Unknown'
            patid = ds.PatientID if 'PatientID' in ds else ''
            patdob = ds.PatientBirthDate if 'PatientBirthDate' in ds else ''
            patsex = ds.PatientSex if 'PatientSex' in ds else ''
            nstudies = ds.NumberOfPatientRelatedStudies if 'NumberOfPatientRelatedStudies' in ds else 0
            responses.append(
                PatientLevelFields(patname, patid, patdob, patsex, nstudies))

    assoc.Release(0)
    ae.Quit()

    return responses
Ejemplo n.º 5
0
def dcm_img_level_find(aet, node, port, laet, patid, studyuid, seriesuid):
    ''' Use pynetdicom to perform a image level query. The result is a list
        of ImageLevelFields records.
    '''
    global msg_id
    msg_id += 1

    # Create application entity and association with remote AE (port number of 0 to stop it putting up a listen)
    ae = AE(laet, port=0, SOPSCU=[PatientRootFindSOPClass], SOPSCP=[])
    ae.start()
    assoc = ae.RequestAssociation({'Address': node, 'Port': port, 'AET': aet})

    # Query object
    d = Dataset()
    d.PatientID = patid
    d.StudyInstanceUID = studyuid
    d.SeriesInstanceUID = seriesuid
    d.SOPInstanceUID = ''
    d.InstanceNumber = ''
    d.QueryRetrieveLevel = 'IMAGE'

    # Request returns a generator
    responses = []
    matches = assoc.PatientRootFindSOPClass.SCU(d, msg_id)
    for state, ds in matches:
        if state == 'Pending':
            patid = ds.PatientID if 'PatientID' in ds else ''
            studyuid = ds.StudyInstanceUID if 'StudyInstanceUID' in ds else ''
            seriesuid = ds.SeriesInstanceUID if 'SeriesInstanceUID' in ds else ''
            imageuid = ds.SOPInstanceUID if 'SOPInstanceUID' in ds else ''
            imagenumber = ds.InstanceNumber if 'InstanceNumber' in ds else ''
            responses.append(ImageLevelFields(imageuid, imagenumber))

    assoc.Release(0)
    ae.Quit()

    return responses
Ejemplo n.º 6
0
# create application entity
MyAE = AE(
    args.aet, args.p,
    [PatientRootFindSOPClass, PatientRootMoveSOPClass, VerificationSOPClass],
    [StorageSOPClass], ts)
MyAE.OnAssociateResponse = OnAssociateResponse
MyAE.OnAssociateRequest = OnAssociateRequest
MyAE.OnReceiveStore = OnReceiveStore
MyAE.start()

# remote application entity
RemoteAE = dict(Address=args.remotehost, Port=args.remoteport, AET=args.aec)

# create association with remote AE
print "Request association"
assoc = MyAE.RequestAssociation(RemoteAE)

# perform a DICOM ECHO
print "DICOM Echo ... ",
st = assoc.VerificationSOPClass.SCU(1)
print 'done with status "%s"' % st

print "DICOM FindSCU ... ",
d = Dataset()
d.PatientsName = args.searchstring
d.QueryRetrieveLevel = "PATIENT"
d.PatientID = "*"
st = assoc.PatientRootFindSOPClass.SCU(d, 1)
print 'done with status "%s"' % st

for ss in st:
Ejemplo n.º 7
0
def _pynetdicom_img_get_worker(aet, node, port, laet, patid, studyuid,
                               seriesuid, imageuid, savedir, queue, returns):
    ''' Use pynetdicom to perform a series level c-get fetch. This is to be run in a separate worker thread.
        The c-store callbacks save the images and push a CStoreResponse object onto a queue for the main thread.
        The function returns normally, which will lead to the threading terminating. This is detected by the
        parent thread.
    '''
    global msg_id
    msg_id += 1

    # a slight kludge as python 2.7 doesn't have 'nonlocal' qualifier
    image_counter = [0]

    # The callback function for C-STORE sub-operations
    def on_receive_store(cget_obj, ds):
        try:
            # print 'C-STORE callback(cget=%s,instno=%d)' % (cget_obj, ds.InstanceNumber)
            # This is a bit of a hack but we need to add some file-meta
            file_meta = Dataset()
            file_meta.add_new((2, 0x01), 'OB',
                              b'\0\1')  # FileMetaInformationVersion
            file_meta.add_new((2, 0x02), 'UI',
                              ds.SOPClassUID)  # MediaStorageSOPClassUID
            file_meta.add_new((2, 0x03), 'UI',
                              ds.SOPInstanceUID)  # MediaStorageSOPInstanceUID
            file_meta.add_new((2, 0x10), 'UI',
                              ExplicitVRLittleEndian)  # TransferSyntaxUID
            file_meta.add_new((2, 0x12), 'UI',
                              '1.2.40.0.13.1.1')  # ImplementationClassUID
            file_meta.add_new((2, 0x13), 'SH',
                              'pynetdicom')  # ImplementationVersionName
            ds.file_meta = file_meta
            # and specify the encoding
            ds.is_implicit_VR = False
            ds.is_little_endian = True

            save_path = os.path.join(savedir,
                                     '%05d.dcm' % (image_counter[0] + 1))
            # the WriteLikeOriginal=False flag is need to get preamble etc right
            ds.save_as(filename=save_path, WriteLikeOriginal=False)
            image_counter[0] += 1
            pcid = image_counter[0]  # for the sake of argument
            # actually what we want here is the message object so we can extract the no of operations, status etc
            status = 0
            queue.put(CStoreResponse(pcid, status))

        except Exception as e:
            # print 'Error saving: C-STORE callback(cget=%s, instno=%d), saving to %s [%s]' % (cget_obj, ds.InstanceNumber, save_path, e)
            print('Error Saving: %s' % e)
            return 1  # ?? RHD
        # zero corresponds to DICOM Success
        return 0

    # Create application entity and association with remote AE (port number of 0 to stop it putting up a listen)
    ae = AE(laet,
            port=0,
            SOPSCU=[PatientRootGetSOPClass],
            SOPSCP=[
                RTPlanStorageSOPClass, CTImageStorageSOPClass,
                MRImageStorageSOPClass, RTImageStorageSOPClass
            ])
    ae.OnReceiveStore = on_receive_store
    ae.start()
    assoc = ae.RequestAssociation({'Address': node, 'Port': port, 'AET': aet})

    # Query object
    d = Dataset()
    d.PatientID = str(patid)
    d.StudyInstanceUID = str(studyuid)
    d.SeriesInstanceUID = str(seriesuid)
    d.SOPInstanceUID = str(imageuid)
    d.QueryRetrieveLevel = 'IMAGE'

    st_ds = assoc.PatientRootGetSOPClass.SCU(d, msg_id)
    if st_ds is not None:
        for status, ds in st_ds:
            pass
            # print 'status = %s, dataset = %s' % (status, ds)
    # print 'Done'

    returns.append(status)
    return
Ejemplo n.º 8
0
class ApplicationEntityService(object):
    """DICOM application entity service
    """

    __metaclass__ = SingletonType

    def __init__(self):
        """Default constructor
        """
        # Setup logger - use config file
        self._logger = logging.getLogger(__name__)
        logging.config.fileConfig('logging.ini',
                                  disable_existing_loggers=False)

        self._ae = None
        self._downloadDir = ""
        self._guiThread = None
        self._fileCounter = 0

    def __del__(self):
        """Default destructor
        """
        if self.isReady:
            self.quit()

########  ########   #######  ########  ######## ########  ######## #### ########  ######
##     ## ##     ## ##     ## ##     ## ##       ##     ##    ##     ##  ##       ##    ##
##     ## ##     ## ##     ## ##     ## ##       ##     ##    ##     ##  ##       ##
########  ########  ##     ## ########  ######   ########     ##     ##  ######    ######
##        ##   ##   ##     ## ##        ##       ##   ##      ##     ##  ##             ##
##        ##    ##  ##     ## ##        ##       ##    ##     ##     ##  ##       ##    ##
##        ##     ##  #######  ##        ######## ##     ##    ##    #### ########  ######

    @property
    def ae(self):
        """AE Getter
        """
        return self._ae

    @property
    def isReady(self):
        """Is ready Getter
        """
        return self._ae is not None

    @property
    def downloadDir(self):
        """Download directory Getter
        """
        return self._downloadDir

    @downloadDir.setter
    def downloadDir(self, value):
        """Download directory Setter
        """
        self._downloadDir = value

##     ## ######## ######## ##     ##  #######  ########   ######
###   ### ##          ##    ##     ## ##     ## ##     ## ##    ##
#### #### ##          ##    ##     ## ##     ## ##     ## ##
## ### ## ######      ##    ######### ##     ## ##     ##  ######
##     ## ##          ##    ##     ## ##     ## ##     ##       ##
##     ## ##          ##    ##     ## ##     ## ##     ## ##    ##
##     ## ########    ##    ##     ##  #######  ########   ######

    def init(self, name, port):
        """Initialize and start AE
        """
        # setup AE
        self._ae = AE(name, port, [
            PatientRootFindSOPClass, StudyRootFindSOPClass,
            PatientRootMoveSOPClass, StudyRootMoveSOPClass,
            VerificationSOPClass
        ], [StorageSOPClass, VerificationSOPClass])

        self._ae.OnAssociateRequest = self.onAssociateRequest
        self._ae.OnAssociateResponse = self.onAssociateResponse
        self._ae.OnReceiveStore = self.onReceiveStore
        self._ae.OnReceiveEcho = self.onReceiveEcho

        self._ae.start()

        self._logger.info("AE created: " + name + ":" + str(port))

    def quit(self):
        """Quite AE
        """
        self._ae.Quit()

    def requestAssociation(self, remoteAe):
        """Create association with remote AE
        """
        self._logger.debug("Request association")

        return self._ae.RequestAssociation(remoteAe)

    def echo(self, association):
        """Perform a DICOM echo
        """
        status = association.VerificationSOPClass.SCU(1)
        self._logger.debug("Echo done with status: " + str(status))
        return status

    def find(self, data, thread=None):
        """Perform DICOM find
        """
        association = data[0]
        queryLvl = data[1]

        arguments = len(data)

        patientNameFilter = ""
        patientIdFilter = "*"
        studyUidFilter = "*"
        seriesUidFilter = "*"

        d = Dataset()

        if (arguments >= 3):
            patientNameFilter = data[2]
        if (arguments >= 4):
            patientIdFilter = data[3]
            d.ModalitiesInStudy = ""
        if (arguments >= 5):
            studyUidFilter = data[4]
        if (arguments >= 6):
            seriesUidFilter = data[5]

        d.QueryRetrieveLevel = queryLvl
        d.PatientsName = patientNameFilter
        d.PatientID = patientIdFilter
        d.PatientSex = ""
        d.PatientBirthDate = ""

        d.StudyInstanceUID = studyUidFilter
        d.AccessionNumber = ""
        d.StudyDescription = ""
        d.StudyDate = ""

        d.SeriesInstanceUID = seriesUidFilter
        d.SeriesDate = ""
        d.SeriesTime = ""
        d.SeriesDescription = ""
        d.Modality = ""

        status = association.PatientRootFindSOPClass.SCU(d, 1)

        self._logger.debug("Find done with status: " + str(status))

        if thread:
            thread.emit(QtCore.SIGNAL("finished(QVariant)"), status)
            return None
        else:
            return status

    def findPatient(self, data, thread=None):
        """Perform DICOM patient find
        """
        association = data[0]
        queryLvl = data[1]

        d = Dataset()
        d.QueryRetrieveLevel = queryLvl

        status = association.PatientRootFindSOPClass.SCU(d, 1)

        self._logger.debug("Find DICOM patinet done with status: " +
                           str(status))

        if thread:
            thread.emit(QtCore.SIGNAL("finished(QVariant)"), status)
            return None
        else:
            return status

    def findStudy(self, data, thread=None):
        """Perform DICOM study find
        """
        association = data[0]
        queryLvl = data[1]

        d = Dataset()
        d.QueryRetrieveLevel = queryLvl

        status = association.StudyRootFindSOPClass.SCU(d, 1)

        self._logger.debug("Find DICOM study done with status: " + str(status))

        if thread:
            thread.emit(QtCore.SIGNAL("finished(QVariant)"), status)
            return None
        else:
            return status

    def queryRetrieveTree(self, data, thread=None):
        """
        """
        rootNode = data[0]  # rootNode
        remoteAe = data[1]  # remoteAe

        self._guiThread = thread
        self._fileCounter = 0

        count = len(rootNode.children)
        downloaded = 0

        thread.emit(QtCore.SIGNAL("log(QString)"),
                    "Retrieving DICOM data can take some time please wait...")

        for patient in rootNode.children:
            if patient.isChecked:
                thread.emit(
                    QtCore.SIGNAL("log(QString)"),
                    "Processing DICOM patient: " + patient.name + " (" +
                    patient.id + ")")
                self.queryRetrievePatient(patient.id, patient.name, remoteAe,
                                          thread)
            else:
                for study in patient.children:
                    if study.isChecked:
                        thread.emit(QtCore.SIGNAL("log(QString)"),
                                    "Processing DICOM study: " + study.suid)
                        self.queryRetrieveStudy()
                    else:
                        for series in study.children:
                            if series.isChecked:
                                thread.emit(
                                    QtCore.SIGNAL("log(QString)"),
                                    "Processing DICOM study: " + series.suid)
                                self.queryRetrieveSeries()

            downloaded = downloaded + 1
            thread.emit(QtCore.SIGNAL("taskUpdated"), [downloaded, count])

        thread.emit(QtCore.SIGNAL('log(QString)'), 'Finished!')
        thread.emit(QtCore.SIGNAL('message(QString)'),
                    "Retrieve job was successful.")

    def queryRetrievePatient(self,
                             patientId,
                             patientName,
                             remoteAe,
                             thread=None):
        """
        """
        queryLvl = "PATIENT"
        association = self._ae.RequestAssociation(remoteAe)
        result = self.find([association, queryLvl, patientName, patientId])

        for entity in result:
            if not entity[1]: continue

            d = Dataset()
            try:
                d.PatientID = entity[1].PatientID
            except Exception, err:
                self._logger.error(str(err))
                continue

            subAssociation = self._ae.RequestAssociation(remoteAe)
            generator = subAssociation.PatientRootMoveSOPClass.SCU(
                d, self._ae.name, 1)

            for subentity in generator:
                self._logger.info(subentity)

            subAssociation.Release(0)

        association.Release(0)
Ejemplo n.º 9
0
class Pacs:
    def __init__(self,
                 port=1234,
                 aet='ACME1',
                 output='out',
                 implicit=None,
                 explicit=None):
        self.remoteAE = None
        self.onDicomSaved = None
        self.import_folder = None
        self.logger = logging.getLogger(__name__)
        if implicit:
            ts = [ImplicitVRLittleEndian]
        elif explicit:
            ts = [ExplicitVRLittleEndian]
        else:
            ts = [
                ExplicitVRLittleEndian, ImplicitVRLittleEndian,
                ExplicitVRBigEndian
            ]
        self.port = port
        self.aet = aet
        self.output = output
        self.logger.info("Creating local AE='%s' port=%d" % (aet, port))
        self.MyAE = AE(aet, port, [
            StudyRootFindSOPClass, StudyRootMoveSOPClass,
            PatientRootFindSOPClass, PatientRootMoveSOPClass,
            VerificationSOPClass
        ], [StorageSOPClass], ts)
        self.MyAE.OnAssociateResponse = self.OnAssociateResponse
        self.MyAE.OnAssociateRequest = self.OnAssociateRequest
        self.MyAE.OnReceiveStore = self.OnReceiveStore

    def connect(self, remotehost, remoteport, aec):
        self.remoteAE = dict(Address=remotehost, Port=remoteport, AET=aec)
        self.logger.debug("starting local application entity")
        self.MyAE.start()
        # create association with remote AE
        try:
            self.logger.info("Requesting association to %s" % self.remoteAE)
            assoc = self.MyAE.RequestAssociation(self.remoteAE)
            # perform a DICOM ECHO
            st = assoc.VerificationSOPClass.SCU(1)
        except:
            self.logger.critical(
                "Unable to get association with %s, is the server running?" %
                self.remoteAE)
            raise
        self.logger.info('association done with status "%s"' % st)
        now = datetime.now()
        self.import_folder = os.path.join(self.output,
                                          now.strftime('%Y.%m.%d:%H:%M:%S'))
        assoc.Release(0)

    def OnAssociateResponse(self, association):
        self.logger.debug("Association response received")

    def OnAssociateRequest(self, association):
        self.logger.debug("Association resquested")
        return True

    def OnReceiveStore(self, SOPClass, ds):
        # do something with dataset. For instance, store it.
        self.logger.debug(
            "Received C-STORE SeriesInstanceUID:'%s', SOPInstanceUID:'%s''" %
            (ds.SeriesInstanceUID, ds.SOPInstanceUID))
        file_meta = Dataset()
        file_meta.MediaStorageSOPClassUID = '1.2.840.10008.5.1.4.1.1.2'
        # !! Need valid UID herecopy_dicom
        file_meta.MediaStorageSOPInstanceUID = "1.2.3"
        # !!! Need valid UIDs here
        file_meta.ImplementationClassUID = "1.2.3.4"
        folder = os.path.join(self.import_folder, ds.StudyID)
        if not os.path.isdir(folder):
            os.makedirs(folder)
        filename = '%s/%s.dcm' % (folder, ds.SOPInstanceUID)
        fileds = FileDataset(filename, {},
                             file_meta=file_meta,
                             preamble="\0" * 128)
        fileds.update(ds)
        fileds.save_as(filename)
        self.logger.info("file %s written" % filename)
        if self.onDicomSaved:
            self.logger.info("calling callback")
            self.onDicomSaved(filename)
        # must return appropriate status
        return SOPClass.Success

    def query(self, dataset):
        assoc = self.MyAE.RequestAssociation(self.remoteAE)
        if dataset.QueryRetrieveLevel == "STUDY":
            st = assoc.StudyRootFindSOPClass.SCU(dataset, 1)
        elif dataset.QueryRetrieveLevel == "PATIENT":
            st = assoc.PatientRootFindSOPClass.SCU(dataset, 1)
        else:
            raise AttributeError("Unsupported PatientRootFindSOPClass " +
                                 dataset.QueryRetrieveLevel)
        items = [ss[1] for ss in st if ss[1]]
        assoc.Release(0)
        return items

    def list_studies(self):
        d = Dataset()
        d.QueryRetrieveLevel = "STUDY"
        d.SeriesInstanceUID = '*'
        return self.query(d)

    def copy_dicom(self, dataset):
        assoc = self.MyAE.RequestAssociation(self.remoteAE)
        gen = assoc.StudyRootMoveSOPClass.SCU(dataset, self.aet, 1)
        for gg in gen:
            # we have to access the item to copy it (it will be done asynchronously)
            self.logger.debug("copying %s" % gg)
            x = gg
        assoc.Release(0)

    def quit(self):
        self.MyAE.Quit()