Ejemplo n.º 1
1
    def test_association_acse_timeout(self):
        """ Check that the Association timeouts are being set correctly """
        scp = AEVerificationSCP()
        scp.ae.acse_timeout = 0
        scp.ae.dimse_timeout = 0
        
        ae = AE(scu_sop_class=[VerificationSOPClass])
        ae.acse_timeout = 0
        ae.dimse_timeout = 0
        assoc = ae.associate('localhost', 11112)
        self.assertTrue(scp.ae.active_associations[0].acse_timeout == 0)
        self.assertTrue(scp.ae.active_associations[0].dimse_timeout == 0)
        self.assertTrue(assoc.acse_timeout == 0)
        self.assertTrue(assoc.dimse_timeout == 0)
        assoc.release()
        
        scp.ae.acse_timeout = 21
        scp.ae.dimse_timeout = 22
        ae.acse_timeout = 31
        ae.dimse_timeout = 32

        assoc = ae.associate('localhost', 11112)
        self.assertTrue(scp.ae.active_associations[0].acse_timeout == 21)
        self.assertTrue(scp.ae.active_associations[0].dimse_timeout == 22)
        self.assertTrue(assoc.acse_timeout == 31)
        self.assertTrue(assoc.dimse_timeout == 32)
        assoc.release()
        
        self.assertRaises(SystemExit, scp.stop)
Ejemplo n.º 2
1
 def test_associate_establish_release(self):
     """ Check SCU Association with SCP """
     scp = AEVerificationSCP()
     
     ae = AE(scu_sop_class=[VerificationSOPClass])
     assoc = ae.associate('localhost', 11112)
     self.assertTrue(assoc.is_established == True)
     
     assoc.release()
     self.assertTrue(assoc.is_established == False)
     
     self.assertRaises(SystemExit, scp.stop)
Ejemplo n.º 3
1
 def test_associate_max_pdu(self):
     """ Check Association has correct max PDUs on either end """
     scp = AEVerificationSCP()
     scp.ae.maximum_pdu_size = 54321
     
     ae = AE(scu_sop_class=[VerificationSOPClass])
     assoc = ae.associate('localhost', 11112, max_pdu=12345)
     
     self.assertTrue(scp.ae.active_associations[0].local_max_pdu == 54321)
     self.assertTrue(scp.ae.active_associations[0].peer_max_pdu == 12345)
     self.assertTrue(assoc.local_max_pdu == 12345)
     self.assertTrue(assoc.peer_max_pdu == 54321)
     
     assoc.release()
     
     # Check 0 max pdu value
     assoc = ae.associate('localhost', 11112, max_pdu=0)
     self.assertTrue(assoc.local_max_pdu == 0)
     self.assertTrue(scp.ae.active_associations[0].peer_max_pdu == 0)
     
     assoc.release()
     self.assertRaises(SystemExit, scp.stop)
Ejemplo n.º 4
1
 def test_on_c_echo_called(self):
     """ Check that SCP AE.on_c_echo() was called """
     scp = AEVerificationSCP()
     
     ae = AE(scu_sop_class=[VerificationSOPClass])
     assoc = ae.associate('localhost', 11112)
     with patch.object(scp.ae, 'on_c_echo') as mock:
         assoc.send_c_echo()
         
     mock.assert_called_with()
     
     assoc.release()
     
     self.assertRaises(SystemExit, scp.stop)
Ejemplo n.º 5
1
 def test_on_c_store_called(self):
     """ Check that SCP AE.on_c_store(dataset) was called """
     scp = AEStorageSCP()
     
     ae = AE(scu_sop_class=StorageSOPClassList)
     assoc = ae.associate('localhost', 11112)
     #with patch.object(scp.ae, 'on_c_store') as mock:
     #    assoc.send_c_store(dataset)
         
     #mock.assert_called_with()
     
     assoc.release()
     
     self.assertRaises(SystemExit, scp.stop)
Ejemplo n.º 6
1
 def test_ae_release_assoc(self):
     """ Association releases OK """
     # Start Verification SCP
     scp = AEVerificationSCP()
     
     ae = AE(scu_sop_class=[VerificationSOPClass])
     
     # Test N associate/release cycles
     for ii in range(10):
         assoc = ae.associate('localhost', 11112)
         self.assertTrue(assoc.is_established)
         
         if assoc.is_established:
             assoc.release()
             self.assertTrue(assoc.is_established == False)
             self.assertTrue(assoc.is_released == True)
             self.assertTrue(ae.active_associations == [])
     
     # Kill Verification SCP (important!)
     self.assertRaises(SystemExit, scp.stop)
Ejemplo n.º 7
0
handler.setLevel(logging.INFO)
formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)

console = logging.StreamHandler()
console.setLevel(logging.INFO)
logger.addHandler(handler)
logger.addHandler(console)

ae = AE(ae_title=b'MY_STORAGE_SCU')
ae.add_requested_context(UID('1.2.840.10008.5.1.4.1.1.3.1'))
# ae.add_requested_context(UltrasoundMultiframeImageStorage)
for cx in ae.requested_contexts:
    print(cx)

# assoc = ae.associate('192.168.3.5', 4100)
assoc = ae.associate('127.0.0.1', 4100)

if assoc.is_established:
    logger.info('assoc is established')
    # dataset = dcmread('./MRI.dcm')
    dataset = dcmread('./IMG00001')
    # `status` is the response from the peer to the store request
    # but may be an empty pydicom Dataset if the peer timed out or
    # sent an invalid dataset.
    status = assoc.send_c_store(dataset)
    assoc.release()
else:
    logger.info('no assoc')
Ejemplo n.º 8
0
def main(args=None):
    """Run the application."""
    if args is not None:
        sys.argv = args

    args = _setup_argparser()

    if args.version:
        print('findscu.py v{}'.format(__version__))
        sys.exit()

    APP_LOGGER = setup_logging(args, 'findscu')
    APP_LOGGER.debug('findscu.py v{0!s}'.format(__version__))
    APP_LOGGER.debug('')

    # Create query (identifier) dataset
    try:
        # If you're looking at this to see how QR Find works then `identifer`
        # is a pydicom Dataset instance with your query keys, e.g.:
        #     identifier = Dataset()
        #     identifier.QueryRetrieveLevel = 'PATIENT'
        #     identifier.PatientName = ''
        identifier = create_dataset(args, APP_LOGGER)
    except Exception as exc:
        APP_LOGGER.exception(exc)
        raise exc
        sys.exit(1)

    # Create application entity
    # Binding to port 0 lets the OS pick an available port
    ae = AE(ae_title=args.calling_aet)

    # Set timeouts
    ae.acse_timeout = args.acse_timeout
    ae.dimse_timeout = args.dimse_timeout
    ae.network_timeout = args.network_timeout

    # Set the Presentation Contexts we are requesting the Find SCP support
    ae.requested_contexts = (QueryRetrievePresentationContexts +
                             BasicWorklistManagementPresentationContexts)

    # Query/Retrieve Information Models
    if args.worklist:
        query_model = ModalityWorklistInformationFind
    elif args.study:
        query_model = StudyRootQueryRetrieveInformationModelFind
    elif args.psonly:
        query_model = PatientStudyOnlyQueryRetrieveInformationModelFind
    else:
        query_model = PatientRootQueryRetrieveInformationModelFind

    # Request association with (QR/BWM) Find SCP
    assoc = ae.associate(args.addr,
                         args.port,
                         ae_title=args.called_aet,
                         max_pdu=args.max_pdu)
    if assoc.is_established:
        # Send C-FIND request, `responses` is a generator
        responses = assoc.send_c_find(identifier, query_model)
        # Used to generate filenames if args.write used
        fname = generate_filename()
        for (status, rsp_identifier) in responses:
            # If `status.Status` is one of the 'Pending' statuses then
            #   `rsp_identifier` is the C-FIND response's Identifier dataset
            if status and status.Status in [0xFF00, 0xFF01]:
                if args.write:
                    rsp_identifier.file_meta = get_file_meta(
                        assoc, query_model)
                    rsp_identifier.save_as(next(fname),
                                           write_like_original=False)

        # Release the association
        assoc.release()
    else:
        sys.exit(1)
Ejemplo n.º 9
0
# Create out identifier (query) dataset
ds = Dataset()
#http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_C.6.html  (PATIENT, STUDY, SERIES, IMAGES)
ds.QueryRetrieveLevel = 'STUDY'
# Unique key for PATIENT level
#ds.StudyDate = '20060722'
#ds[0x0008, 0x0020] = DataElement(0x00080020, 'DA', '20060722')
ds.StudyInstanceUID = '*'
# Unique key for STUDY level
#ds.StudyInstanceUID = '1.3.6.1.4.1.5962.1.2.0.1175775771.5702.0'
# Unique key for SERIES level
# ds.SeriesInstanceUID = '1.2.3.4'

# Associate with peer AE at IP 127.0.0.1 and port 11112
assoc = ae.associate(source_pacs_ip, source_pacs_port, ae_title = source_pacs_ae_title)


if assoc.is_established:
    # Use the C-MOVE service to send the identifier
    responses = assoc.send_c_move(ds, destination_pacs_ae_title, StudyRootQueryRetrieveInformationModelMove)
    for (status, identifier) in responses:
        #status : Failure, Cancel, Warning, Success, Pending
        if status:
            if status.Status == 0xFF00:
                print('Pending')
            elif status.Status == 0x0000:
                print('Success')
                print('Number of Completed Sub-operations ' + str(status.get(0x1021).value))
                print('Number of Failed Sub-operations ' + str(status.get(0x1022).value))
                print('Number of Warning Sub-operations ' + str(status.get(0x1023).value))
Ejemplo n.º 10
0
        else:
            transfer_syntax = [
                ExplicitVRLittleEndian, ImplicitVRLittleEndian,
                DeflatedExplicitVRLittleEndian, ExplicitVRBigEndian
            ]

        for cx in StoragePresentationContexts:
            ae.add_requested_context(cx.abstract_syntax, transfer_syntax)

    if not lfiles:
        APP_LOGGER.warning("No suitable DICOM files found")
        sys.exit()

    # Request association with remote
    assoc = ae.associate(args.addr,
                         args.port,
                         ae_title=args.called_aet,
                         max_pdu=args.max_pdu)
    if assoc.is_established:
        ii = 1
        for fpath in lfiles:
            APP_LOGGER.info('Sending file: {}'.format(fpath))
            try:
                ds = dcmread(fpath)
                status = assoc.send_c_store(ds, ii)
                ii += 1
            except InvalidDicomError:
                APP_LOGGER.error('Bad DICOM file: {}'.format(fpath))
            except ValueError as exc:
                APP_LOGGER.error("Store failed: {}".format(fpath))
            except Exception as exc:
                APP_LOGGER.error("Store failed: {}".format(fpath))
Ejemplo n.º 11
0
    sys.exit()

# Set Transfer Syntax options
transfer_syntax = [
    ExplicitVRLittleEndian, ImplicitVRLittleEndian,
    DeflatedExplicitVRLittleEndian, ExplicitVRBigEndian
]

if args.request_little:
    transfer_syntax = [ExplicitVRLittleEndian]
elif args.request_big:
    transfer_syntax = [ExplicitVRBigEndian]
elif args.request_implicit:
    transfer_syntax = [ImplicitVRLittleEndian]

# Bind to port 0, OS will pick an available port
ae = AE(ae_title=args.calling_aet)

for context in StoragePresentationContexts:
    ae.add_requested_context(context.abstract_syntax, transfer_syntax)

# Request association with remote
assoc = ae.associate(args.peer, args.port, ae_title=args.called_aet)

if assoc.is_established:
    APP_LOGGER.info('Sending file: {0!s}'.format(args.dcmfile_in))

    status = assoc.send_c_store(dataset)

    assoc.release()
Ejemplo n.º 12
0
def send_store(nr_assoc, ds_per_assoc, use_yappi=False):
    """Send a number of sequential C-STORE requests.

    Parameters
    ----------
    nr_assoc : int
        The total number of (sequential) associations that will be made.
    ds_per_assoc : int
        The number of C-STORE requests sent per successful association.
    use_yappi : bool, optional
        True to use the yappi profiler, False otherwise (default).
    """
    if use_yappi:
        init_yappi()

    # Start SCP
    server = start_storescp()
    time.sleep(0.5)

    ae = AE()
    ae.acse_timeout = 5
    ae.dimse_timeout = 5
    ae.network_timeout = 5
    ae.add_requested_context(DATASET.SOPClassUID, ImplicitVRLittleEndian)

    # Start timer
    start_time = time.time()
    run_times = []

    is_successful = True

    for ii in range(nr_assoc):
        if not is_successful:
            break

        assoc = ae.associate('localhost', 11112)

        if assoc.is_established:
            for jj in range(ds_per_assoc):
                try:
                    status = assoc.send_c_store(DATASET)
                    if status and status.Status != 0x0000:
                        is_successful = False
                        break
                except RuntimeError:
                    is_successful = False
                    break

            assoc.release()
            if is_successful:
                run_times.append(time.time() - start_time)
        else:
            is_successful = False
            break

    if is_successful:
        print("C-STORE SCU transferred {} total datasets over {} "
              "association(s) in {:.2f} s".format(nr_assoc * ds_per_assoc,
                                                  nr_assoc,
                                                  time.time() - start_time))
    else:
        print("C-STORE SCU benchmark failed")

    server.terminate()
Ejemplo n.º 13
0
def main(args=None):
    """Run the application."""
    if args is not None:
        sys.argv = args

    args = _setup_argparser()

    if args.version:
        print('storescu.py v{__version__}')
        sys.exit()

    APP_LOGGER = setup_logging(args, 'storescu')
    APP_LOGGER.debug('storescu.py v{__version__}')
    APP_LOGGER.debug('')

    lfiles, badfiles = get_files(args.path, args.recurse)

    for bad in badfiles:
        APP_LOGGER.error("Cannot access path: {bad}")

    ae = AE(ae_title=args.calling_aet)
    ae.acse_timeout = args.acse_timeout
    ae.dimse_timeout = args.dimse_timeout
    ae.network_timeout = args.network_timeout

    if args.required_contexts:
        # Only propose required presentation contexts
        lfiles, contexts = get_contexts(lfiles, APP_LOGGER)
        try:
            for abstract, transfer in contexts.items():
                for tsyntax in transfer:
                    ae.add_requested_context(abstract, tsyntax)
        except ValueError:
            raise ValueError(
                "More than 128 presentation contexts required with "
                "the '--required-contexts' flag, please try again "
                "without it or with fewer files"
            )
    else:
        # Propose the default presentation contexts
        if args.request_little:
            transfer_syntax = [ExplicitVRLittleEndian]
        elif args.request_big:
            transfer_syntax = [ExplicitVRBigEndian]
        elif args.request_implicit:
            transfer_syntax = [ImplicitVRLittleEndian]
        else:
            transfer_syntax = [
                ExplicitVRLittleEndian,
                ImplicitVRLittleEndian,
                DeflatedExplicitVRLittleEndian,
                ExplicitVRBigEndian
            ]

        for cx in StoragePresentationContexts:
            ae.add_requested_context(cx.abstract_syntax, transfer_syntax)

    if not lfiles:
        APP_LOGGER.warning("No suitable DICOM files found")
        sys.exit()

    # Request association with remote
    assoc = ae.associate(
        args.addr, args.port, ae_title=args.called_aet, max_pdu=args.max_pdu
    )
    if assoc.is_established:
        ii = 1
        for fpath in lfiles:
            APP_LOGGER.info('Sending file: {fpath}')
            try:
                ds = dcmread(fpath)
                status = assoc.send_c_store(ds, ii)
                ii += 1
            except InvalidDicomError:
                APP_LOGGER.error('Bad DICOM file: {fpath}')
            except Exception as exc:
                APP_LOGGER.error("Store failed: {fpath}")
                APP_LOGGER.exception(exc)

        assoc.release()
    else:
        sys.exit(1)
Ejemplo n.º 14
0
# Add a requested presentation context
ae.add_requested_context(PatientRootQueryRetrieveInformationModelMove)

# Create out identifier (query) dataset
ds = Dataset()
ds.QueryRetrieveLevel = 'SERIES'
# Unique key for PATIENT level
ds.PatientID = '1234567'
# Unique key for STUDY level
ds.StudyInstanceUID = '1.2.3'
# Unique key for SERIES level
ds.SeriesInstanceUID = '1.2.3.4'

# Associate with peer AE at IP 127.0.0.1 and port 11112
assoc = ae.associate('127.0.0.1', 11112)

if assoc.is_established:
    # Use the C-MOVE service to send the identifier
    responses = assoc.send_c_move(
        ds, b'STORE_SCP', PatientRootQueryRetrieveInformationModelMove)

    for (status, identifier) in responses:
        if status:
            print('C-MOVE query status: 0x{0:04x}'.format(status.Status))

            # If the status is 'Pending' then the identifier is the C-MOVE response
            if status.Status in (0xFF00, 0xFF01):
                print(identifier)
        else:
            print(
Ejemplo n.º 15
0
                   ExplicitVRBigEndian]
                   
if args.request_little:
    transfer_syntax = [ExplicitVRLittleEndian]
elif args.request_big:
    transfer_syntax = [ExplicitVRBigEndian]
elif args.request_implicit:
    transfer_syntax = [ImplicitVRLittleEndian]

# Bind to port 0, OS will pick an available port
ae = AE(ae_title=args.calling_aet,
        port=0,
        scu_sop_class=StorageSOPClassList,
        scp_sop_class=[],
        transfer_syntax=transfer_syntax)

# Request association with remote
assoc = ae.associate(args.peer, args.port, args.called_aet)

if assoc.is_established:
    logger.info('Sending file: %s' %args.dcmfile_in)
    
    status = assoc.send_c_store(dataset)
    
    assoc.release()

# Quit
ae.quit()


Ejemplo n.º 16
0
# We need to supply a Unique Key Attribute for each level above the
#   Query/Retrieve level
ds = Dataset()
ds.QueryRetrieveLevel = 'SERIES'
# Unique key for PATIENT level
ds.PatientID = '8435'
# Unique key for STUDY level
ds.StudyInstanceUID = '1.2.3'
# Unique key for SERIES level
ds.SeriesInstanceUID = '1.2.3.4'
ds.SOPInstanceUID = '1.2.3'
ds.SOPClassUID = '1.2.840.10008.5.1.4.1.1.2'

# Associate with peer AE at IP 127.0.0.1 and port 11112
assoc = ae.associate('medicac.fortiddns.com',
                     4006,
                     ext_neg=[role],
                     evt_handlers=handlers)

if assoc.is_established:
    # Use the C-GET service to send the identifier
    responses = assoc.send_c_get(ds, StudyRootQueryRetrieveInformationModelGet)

    for (status, identifier) in responses:
        if status:
            print('C-GET query status: 0x{0:04x}'.format(status.Status))

            # If the status is 'Pending' then `identifier` is the C-GET response
            if status.Status in (0xFF00, 0xFF01):
                print(identifier)
        else:
            print(
Ejemplo n.º 17
0
def main(args=None):
    """Run the application."""
    if args is not None:
        sys.argv = args

    args = _setup_argparser()

    if args.version:
        print('getscu.py v{}'.format(__version__))
        sys.exit()

    APP_LOGGER = setup_logging(args, 'getscu')
    APP_LOGGER.debug('getscu.py v{0!s}'.format(__version__))
    APP_LOGGER.debug('')

    # Create query (identifier) dataset
    try:
        # If you're looking at this to see how QR Get works then `identifer`
        # is a pydicom Dataset instance with your query keys, e.g.:
        #     identifier = Dataset()
        #     identifier.QueryRetrieveLevel = 'PATIENT'
        #     identifier.PatientName = '*'
        identifier = create_dataset(args, APP_LOGGER)
    except Exception as exc:
        APP_LOGGER.exception(exc)
        sys.exit(1)

    # Exclude these SOP Classes
    _exclusion = [
        PlannedImagingAgentAdministrationSRStorage,
        PerformedImagingAgestAdministrationSRStorage,
        EncapsulatedSTLStorage,
    ]
    store_contexts = [
        cx for cx in StoragePresentationContexts
        if cx.abstract_syntax not in _exclusion
    ]

    # Create application entity
    # Binding to port 0 lets the OS pick an available port
    ae = AE(ae_title=args.calling_aet)
    ae.acse_timeout = args.acse_timeout
    ae.dimse_timeout = args.dimse_timeout
    ae.network_timeout = args.network_timeout

    ext_neg = []
    ae.add_requested_context(PatientRootQueryRetrieveInformationModelGet)
    ae.add_requested_context(StudyRootQueryRetrieveInformationModelGet)
    ae.add_requested_context(PatientStudyOnlyQueryRetrieveInformationModelGet)
    for cx in store_contexts:
        ae.add_requested_context(cx.abstract_syntax)
        # Add SCP/SCU Role Selection Negotiation to the extended negotiation
        # We want to act as a Storage SCP
        ext_neg.append(build_role(cx.abstract_syntax, scp_role=True))

    if args.study:
        query_model = StudyRootQueryRetrieveInformationModelGet
    elif args.psonly:
        query_model = PatientStudyOnlyQueryRetrieveInformationModelGet
    else:
        query_model = PatientRootQueryRetrieveInformationModelGet

    # Request association with remote
    assoc = ae.associate(args.addr,
                         args.port,
                         ae_title=args.called_aet,
                         ext_neg=ext_neg,
                         evt_handlers=[(evt.EVT_C_STORE, handle_store,
                                        [args, APP_LOGGER])],
                         max_pdu=args.max_pdu)

    if assoc.is_established:
        # Send query
        responses = assoc.send_c_get(identifier, query_model)
        for (status, rsp_identifier) in responses:
            # If `status.Status` is one of the 'Pending' statuses then
            #   `rsp_identifier` is the C-GET response's Identifier dataset
            if status and status.Status in [0xFF00, 0xFF01]:
                # `rsp_identifier` is a pydicom Dataset containing a query
                # response. You may want to do something interesting here...
                pass

        assoc.release()
    else:
        sys.exit(1)
Ejemplo n.º 18
0
# -*- coding;utf-8 -*-

from pynetdicom import AE

ae = AE()
ae.add_requested_context('1.2.840.10008.1.1')
assoc = ae.associate('localhost', 11112)
if assoc.is_established:
    print('Association established with Echo SCP!')
    assoc.release()
else:
    # Association rejected, aborted or never connected
    print('Failed to associate')
Ejemplo n.º 19
0
console = logging.StreamHandler()
console.setLevel(logging.INFO)
logger.addHandler(console)

ds = dcmread('/Volumes/Transcend/mediclouds/PACS/MRI.dcm')
# ds = dcmread('/Volumes/Transcend/mediclouds/PACS/IMG00001')
ae = AE(ae_title=b'ilab_scu')

ae.requested_contexts = StoragePresentationContexts
# ae.add_requested_context(VerificationPresentationContexts)
# ae.add_requested_context(VerificationSOPClass)

# for cx in ae.requested_contexts:
#     print(cx)

assoc = ae.associate('192.168.3.5', 4100, ae_title=b'lkjds')

if assoc.is_established:
    logger.info('assoc is established')
    dataset = dcmread('./MRI.dcm')
    # dataset = dcmread('./IMG00001')
    # `status` is the response from the peer to the store request
    # but may be an empty pydicom Dataset if the peer timed out or
    # sent an invalid dataset.
    status = assoc.send_c_store(ds, 1, 1)
    assoc.release()
else:
    logger.info('no assoc')

# if assoc.is_established:
#     print('Association connected')
Ejemplo n.º 20
0
def main(args=None):
    """Run the application."""
    if args is not None:
        sys.argv = args

    args = _setup_argparser()

    if args.version:
        print(f'movescu.py v{__version__}')
        sys.exit()

    APP_LOGGER = setup_logging(args, 'movescu')
    APP_LOGGER.debug(f'movescu.py v{__version__}')
    APP_LOGGER.debug('')

    # Create query (identifier) dataset
    try:
        # If you're looking at this to see how QR Move works then `identifer`
        # is a pydicom Dataset instance with your query keys, e.g.:
        #     identifier = Dataset()
        #     identifier.QueryRetrieveLevel = 'PATIENT'
        #     identifier.PatientName = '*'
        identifier = create_dataset(args, APP_LOGGER)
    except Exception as exc:
        APP_LOGGER.exception(exc)
        sys.exit(1)

    # Create application entity
    ae = AE()

    # Start the Store SCP (optional)
    scp = None
    if args.store:
        transfer_syntax = ALL_TRANSFER_SYNTAXES[:]
        store_handlers = [(evt.EVT_C_STORE, handle_store, [args, APP_LOGGER])]
        ae.ae_title = args.store_aet
        for cx in AllStoragePresentationContexts:
            ae.add_supported_context(cx.abstract_syntax, transfer_syntax)

        scp = ae.start_server(('', args.store_port),
                              block=False,
                              evt_handlers=store_handlers)

    ae.ae_title = args.calling_aet
    ae.acse_timeout = args.acse_timeout
    ae.dimse_timeout = args.dimse_timeout
    ae.network_timeout = args.network_timeout
    ae.requested_contexts = QueryRetrievePresentationContexts
    ae.supported_contexts = []

    # Query/Retrieve Information Models
    if args.study:
        query_model = StudyRootQueryRetrieveInformationModelMove
    elif args.psonly:
        query_model = PatientStudyOnlyQueryRetrieveInformationModelMove
    else:
        query_model = PatientRootQueryRetrieveInformationModelMove

    # Extended Negotiation
    ext_neg = []
    ext_opts = [args.relational_retrieval, args.enhanced_conversion]
    if any(ext_opts):
        app_info = b''
        for option in ext_opts:
            app_info += b'\x01' if option else b'\x00'

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = query_model
        item.service_class_application_information = app_info
        ext_neg = [item]

    # Request association with remote AE
    assoc = ae.associate(args.addr,
                         args.port,
                         ae_title=args.called_aet,
                         max_pdu=args.max_pdu,
                         ext_neg=ext_neg)
    if assoc.is_established:
        # Send query
        move_aet = args.move_aet or args.calling_aet
        responses = assoc.send_c_move(identifier, move_aet, query_model)
        for (status, rsp_identifier) in responses:
            # If `status.Status` is one of the 'Pending' statuses then
            #   `rsp_identifier` is the C-MOVE response's Identifier dataset
            if status and status.Status in [0xFF00, 0xFF01]:
                # `rsp_identifier` is a pydicom Dataset containing a query
                # response. You may want to do something interesting here...
                pass

        assoc.release()
        _EXIT_VALUE = 0
    else:
        _EXIT_VALUE = 1

    # Shutdown the Storage SCP (if used)
    if scp:
        scp.shutdown()

    sys.exit(_EXIT_VALUE)
Ejemplo n.º 21
0
def _send_ctimage(hostname, port, transfersyntax):
    ae = AE()
    ae.add_requested_context(CTImageStorage, transfersyntax)
    assoc = ae.associate(hostname, int(port))
    return assoc
Ejemplo n.º 22
0
            LOGGER.error("    {0!s}".format(os.path.dirname(filename)))
            LOGGER.error('Directory may not exist or you may not have write '
                         'permission')
            # Failed - Out of Resources - IOError
            status_ds.Status = 0xA700
        except:
            LOGGER.error('Could not write file to specified directory:')
            LOGGER.error("    {0!s}".format(os.path.dirname(filename)))
            # Failed - Out of Resources - Miscellaneous error
            status_ds.Status = 0xA701

    return status_ds


ae.on_c_store = on_c_store

# Request association with remote
assoc = ae.associate(args.peer,
                     args.port,
                     ae_title=args.called_aet,
                     ext_neg=ext_neg)

# Send query
if assoc.is_established:
    response = assoc.send_c_get(d, query_model=query_model)

    for status, identifier in response:
        pass

    assoc.release()
Ejemplo n.º 23
0
        # Add SCP/SCU Role Selection Negotiation to the extended negotiation
        # We want to act as a Storage SCP
        ext_neg.append(build_role(cx.abstract_syntax, scp_role=True))

    if args.study:
        query_model = StudyRootQueryRetrieveInformationModelGet
    elif args.psonly:
        query_model = PatientStudyOnlyQueryRetrieveInformationModelGet
    else:
        query_model = PatientRootQueryRetrieveInformationModelGet

    # Request association with remote
    assoc = ae.associate(args.addr,
                         args.port,
                         ae_title=args.called_aet,
                         ext_neg=ext_neg,
                         evt_handlers=[(evt.EVT_C_STORE, handle_store,
                                        [args, APP_LOGGER])],
                         max_pdu=args.max_pdu)

    if assoc.is_established:
        # Send query
        responses = assoc.send_c_get(identifier, query_model)
        for (status, rsp_identifier) in responses:
            # If `status.Status` is one of the 'Pending' statuses then
            #   `rsp_identifier` is the C-GET response's Identifier dataset
            if status and status.Status in [0xFF00, 0xFF01]:
                # `rsp_identifier` is a pydicom Dataset containing a query
                # response. You may want to do something interesting here...
                pass
Ejemplo n.º 24
0
        scp_sop_class=StorageSOPClassList, 
        transfer_syntax=[ExplicitVRLittleEndian])

# Set the extended negotiation SCP/SCU role selection to allow us to receive
#   C-STORE requests for the supported SOP classes
ext_neg = []
for context in ae.presentation_contexts_scu:
    tmp = SCP_SCU_RoleSelectionNegotiation()
    tmp.sop_class_uid = context.AbstractSyntax
    tmp.scu_role = False
    tmp.scp_role = True
    
    ext_neg.append(tmp)

# Request association with remote
assoc = ae.associate(args.peer, args.port, args.called_aet, ext_neg=ext_neg)

# Create query dataset
d = Dataset()
d.PatientsName = '*'
d.QueryRetrieveLevel = "PATIENT"

if args.patient:
    query_model = 'P'
elif args.study:
    query_model = 'S'
elif args.psonly:
    query_model = 'O'
else:
    query_model = 'P'
Ejemplo n.º 25
0
class Mover(object):
    """docstring for DCMover"""
    def __init__(self, config):

        # Initialize the server configuration for the DC Mover

        self.client_name = config['client_name']
        self.client_port = config['client_port']

        self.host_ip = config['host_ip']
        self.host_port = config['host_port']

        # Initialize the settings for the mover

        self.query_model = config['query_model']
        self.mv_brk_cnt = config['query_break_count']

        # Start ApplicationEntity for communication with PACS

        self.ae = AE(ae_title=self.client_name)

        # Adding contexts as required

        self.ae.add_requested_context('1.2.840.10008.1.1')  # Add echo context
        if self.query_model == 'S':
            self.ae.add_requested_context(
                StudyRootQueryRetrieveInformationModelMove)
            self.ae.add_requested_context(
                StudyRootQueryRetrieveInformationModelFind)
        elif self.query_model == 'P':
            self.ae.add_requested_context(
                PatientRootQueryRetrieveInformationModelMove)
            self.ae.add_requested_context(
                PatientRootQueryRetrieveInformationModelFind)
        else:
            print('ERROR: Query model not recognized.')

        # Associate ApplicationEntity with PACS

        self.assoc = self.ae.associate(self.host_ip, self.host_port)
        self.currently_associated = self.assoc_check()

    def assoc_check(self, print_status=False):

        if self.assoc.is_established:
            if print_status:
                print('SUCCESS: associated with PACS entity')
            return True
        else:
            if print_status:
                print('FAILURE: not associated with PACS entity')
            return False

    def dictify(self, ds):
        """Turn a pydicom Dataset into a dict with keys derived from the Element keywords.

        Source: https://github.com/pydicom/pydicom/issues/319"

        Parameters
        ----------
        ds : pydicom.dataset.Dataset
            The Dataset to dictify

        Returns
        -------
        output : dict
        """
        output = dict()
        for elem in ds:
            if elem.VR != 'SQ':
                output[elem.keyword] = str(elem.value)
            else:
                output[elem.keyword] = [self.dictify(item) for item in elem]
        return output

    @staticmethod
    def make_qry_ds(qry):

        ds = Dataset()

        for i in qry:
            setattr(ds, i, qry[i])

        return ds

    def send_c_move(self, qry_dict):

        qry_ds = self.make_qry_ds(qry_dict)
        qry_response = {'status': list(), 'data': list()}
        responses = self.assoc.send_c_move(qry_ds,
                                           self.client_name,
                                           query_model=self.query_model)

        cnt = 0

        for status, ds in responses:

            status_dict = self.dictify(status)
            status_dict['status_category'] = code_to_category(status.Status)
            qry_response['status'].append(status_dict)

            if ds:
                data_dict = self.dictify(ds)
                qry_response['data'].append(data_dict)

            if cnt == self.mv_brk_cnt - 1:
                if 'NumberOfCompletedSuboperations' in qry_response['status']:
                    if sum(
                            int(i['NumberOfCompletedSuboperations'])
                            for i in qry_response['status']) == 0:
                        qry_response['status'].append({
                            'Status':
                            'BREAK @ COUNT ={}'.format(self.mv_brk_cnt)
                        })
                        print(
                            'ABORTING MOVE: {} STATUSES RECEIVED WITHOUT FILE MOVEMENT'
                            .format(self.mv_brk_cnt))
                        break

            cnt += 1
        return qry_response

    def send_c_echo(self):

        status = self.assoc.send_c_echo()
        qry_response = {
            'status': {
                'code': status.Status,
                'category': code_to_category(status.Status)
            }
        }

        return qry_response

    def send_c_find(self, qry_dict):

        qry_ds = self.make_qry_ds(qry_dict)
        qry_response = {'status': list(), 'data': list()}
        responses = self.assoc.send_c_find(qry_ds,
                                           query_model=self.query_model)

        for status, ds in responses:

            status_dict = {
                'code': status.Status,
                'category': code_to_category(status.Status)
            }
            qry_response['status'].append(status_dict)

            if ds:
                data_dict = self.dictify(ds)
                qry_response['data'].append(data_dict)

        return qry_response