Esempio n. 1
0
    def test_keyword_exception(self):
        """Test exception is raised by bad keyword."""
        Args = namedtuple("args", ["keyword", "file"])
        args = Args(["BadPatientName=*"], None)

        msg = r"Unable to parse element path component"
        with pytest.raises(ValueError, match=msg):
            create_dataset(args)
Esempio n. 2
0
    def test_file_read_exception(self):
        """Test exception is raised by bad file read."""
        Args = namedtuple("args", ["keyword", "file"])
        args = Args([], "no_such_file")

        # General exception
        msg = r"No such file or directory"
        with pytest.raises(Exception, match=msg):
            create_dataset(args)
Esempio n. 3
0
    def test_file_read_exception(self):
        """Test exception is raised by bad file read."""
        Args = namedtuple('args', ['keyword', 'file'])
        args = Args([], 'no_such_file')

        # General exception
        msg = r"No such file or directory"
        with pytest.raises(Exception, match=msg):
            create_dataset(args)
Esempio n. 4
0
    def test_element_new(self):
        """Test creating an element using keywords."""
        Args = namedtuple("args", ["keyword", "file"])
        args = Args(["PatientName=*"], None)
        ds = create_dataset(args)

        ref = Dataset()
        ref.PatientName = "*"

        assert ds == ref
Esempio n. 5
0
    def test_element_new(self):
        """Test creating an element using keywords."""
        Args = namedtuple('args', ['keyword', 'file'])
        args = Args(['PatientName=*'], None)
        ds = create_dataset(args)

        ref = Dataset()
        ref.PatientName = '*'

        assert ds == ref
Esempio n. 6
0
    def test_sequence_new(self):
        """Test creating a sequence using keywords."""
        Args = namedtuple("args", ["keyword", "file"])
        args = Args(["BeamSequence[0].PatientName=*"], None)
        ds = create_dataset(args)

        ref = Dataset()
        ref.BeamSequence = [Dataset()]
        ref.BeamSequence[0].PatientName = "*"

        assert ds == ref
Esempio n. 7
0
    def test_sequence_new(self):
        """Test creating a sequence using keywords."""
        Args = namedtuple('args', ['keyword', 'file'])
        args = Args(['BeamSequence[0].PatientName=*'], None)
        ds = create_dataset(args)

        ref = Dataset()
        ref.BeamSequence = [Dataset()]
        ref.BeamSequence[0].PatientName = '*'

        assert ds == ref
Esempio 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(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(("localhost", 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)
Esempio n. 9
0
def main(args=None):
    """Run the application."""
    if args is not None:
        sys.argv = args

    args = _setup_argparser()

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

    APP_LOGGER = setup_logging(args, "getscu")
    APP_LOGGER.debug(f"getscu.py v{__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 = [
        EncapsulatedSTLStorage,
        EncapsulatedOBJStorage,
        EncapsulatedMTLStorage,
    ]
    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

    # Extended Negotiation - SCP/SCU Role Selection
    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

    # Extended Negotiation - SOP Class Extended
    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.append(item)

    # 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)
Esempio n. 10
0
def main(args=None):
    """Run the application."""
    if args is not None:
        sys.argv = args

    args = _setup_argparser()

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

    APP_LOGGER = setup_logging(args, "findscu")
    APP_LOGGER.debug(f"findscu.py v{__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)
        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

    # Extended Negotiation
    ext_neg = []
    ext_opts = [
        args.relational_query,
        args.dt_matching,
        args.fuzzy_names,
        args.timezone_adj,
        args.enhanced_conversion,
    ]
    if not args.worklist and 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]
    elif args.worklist and any([args.fuzzy_names, args.timezone_adj]):
        app_info = b"\x01\x01"
        for option in [args.fuzzy_names, args.timezone_adj]:
            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 (QR/BWM) Find SCP
    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 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)
Esempio n. 11
0
    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
Esempio n. 12
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)