def test_message_to_primitive_c_find(self): """Test converting C_FIND_RQ to C_FIND primitive.""" msg = C_FIND_RQ() for data in [c_find_rq_cmd, c_find_rq_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() self.assertTrue(isinstance(primitive, C_FIND)) self.assertTrue(isinstance(primitive.Identifier, BytesIO)) self.assertTrue(primitive.AffectedSOPClassUID == UID('1.2.840.10008.5.1.4.1.1.2')) self.assertTrue(primitive.Priority == 2) self.assertTrue(primitive.MessageID == 7) ds = decode(primitive.Identifier, True, True) self.assertEqual(ds.QueryRetrieveLevel, 'PATIENT') self.assertEqual(ds.PatientID, '*') msg = C_GET_RSP() for data in [c_find_rsp_cmd, c_find_rsp_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() self.assertTrue(isinstance(primitive, C_FIND)) self.assertTrue(isinstance(primitive.Identifier, BytesIO)) self.assertTrue(primitive.AffectedSOPClassUID == UID('1.2.840.10008.5.1.4.1.1.2')) self.assertTrue(primitive.Status == 65280) ds = decode(primitive.Identifier, True, True) self.assertEqual(ds.QueryRetrieveLevel, 'PATIENT') self.assertEqual(ds.RetrieveAETitle, 'FINDSCP') self.assertEqual(ds.PatientName, 'ANON^A^B^C^D')
def test_assignment(self): """ Check assignment works correctly """ primitive = N_EVENT_REPORT() # AffectedSOPClassUID primitive.AffectedSOPClassUID = '1.1.1' assert primitive.AffectedSOPClassUID == UID('1.1.1') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPClassUID = UID('1.1.2') assert primitive.AffectedSOPClassUID == UID('1.1.2') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPClassUID = b'1.1.3' assert primitive.AffectedSOPClassUID == UID('1.1.3') assert isinstance(primitive.AffectedSOPClassUID, UID) # AffectedSOPInstanceUID primitive.AffectedSOPInstanceUID = b'1.2.1' assert primitive.AffectedSOPInstanceUID == UID('1.2.1') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPInstanceUID = UID('1.2.2') assert primitive.AffectedSOPInstanceUID == UID('1.2.2') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPInstanceUID = '1.2.3' assert primitive.AffectedSOPInstanceUID == UID('1.2.3') assert isinstance(primitive.AffectedSOPClassUID, UID) # Event Information ds = Dataset() ds.PatientID = '1234567' primitive.EventInformation = BytesIO(encode(ds, True, True)) ds = decode(primitive.EventInformation, True, True) assert ds.PatientID == '1234567' # Event Reply ds = Dataset() ds.PatientID = '123456' primitive.EventReply = BytesIO(encode(ds, True, True)) ds = decode(primitive.EventReply, True, True) assert ds.PatientID == '123456' # Event Type ID primitive.EventTypeID = 0x0000 assert primitive.EventTypeID == 0x0000 # MessageID primitive.MessageID = 11 assert 11 == primitive.MessageID # MessageIDBeingRespondedTo primitive.MessageIDBeingRespondedTo = 13 assert 13 == primitive.MessageIDBeingRespondedTo # Status primitive.Status = 0x0000 assert primitive.Status == 0x0000
def test_message_to_primitive_c_store(self): """Test converting C_STORE_RQ and _RSP to C_STORE primitive.""" msg = C_STORE_RQ() for data in [c_store_rq_cmd, c_store_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() assert isinstance(primitive, C_STORE) assert isinstance(primitive.DataSet, BytesIO) assert primitive.AffectedSOPClassUID == UID('1.1.1') assert primitive.AffectedSOPInstanceUID == UID('1.2.1') assert primitive.Priority == 2 assert primitive.MoveOriginatorApplicationEntityTitle == b'UNITTEST ' assert primitive.MoveOriginatorMessageID == 3 ds = decode(primitive.DataSet, True, True) assert ds.PatientName == 'Tube^HeNe' assert ds.PatientID == 'Test1101' msg = C_STORE_RSP() p_data = P_DATA() p_data.presentation_data_value_list.append([0, c_store_rsp_cmd]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() assert isinstance(primitive, C_STORE) assert primitive.DataSet is None for elem in msg.command_set: if hasattr(primitive, elem.keyword): item = getattr(primitive, elem.keyword) assert item == elem.value
def test_implicit_little(self): """Test decoding using implicit VR little endian.""" bytestring = BytesIO() bytestring.write(b'\x10\x00\x10\x00\x0e\x00\x00\x00\x43\x49' \ b'\x54\x49\x5a\x45\x4e\x5e\x53\x6e\x69\x70' \ b'\x73\x20') ds = decode(bytestring, True, True) self.assertEqual(ds.PatientName, 'CITIZEN^Snips')
def test_explicit_big(self): """Test decoding using explicit VR big endian.""" bytestring = BytesIO() bytestring.write(b'\x00\x10\x00\x10\x50\x4e\x00\x0e\x43\x49' \ b'\x54\x49\x5a\x45\x4e\x5e\x53\x6e\x69\x70' \ b'\x73\x20') ds = decode(bytestring, False, False) self.assertEqual(ds.PatientName, 'CITIZEN^Snips')
def test_explicit_little(self): """Test decoding using explicit VR little endian.""" bytestring = BytesIO() bytestring.write(b'\x10\x00\x10\x00\x50\x4e\x0e\x00\x43\x49' \ b'\x54\x49\x5a\x45\x4e\x5e\x53\x6e\x69\x70' \ b'\x73\x20') ds = decode(bytestring, False, True) assert ds.PatientName == 'CITIZEN^Snips'
def test_message_to_primitive_c_move(self): """Test converting C_MOVE_RQ to C_MOVE primitive.""" msg = C_MOVE_RQ() for data in [c_move_rq_cmd, c_move_rq_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() assert isinstance(primitive, C_MOVE) assert isinstance(primitive.Identifier, BytesIO) assert primitive.AffectedSOPClassUID == UID( '1.2.840.10008.5.1.4.1.1.2') assert primitive.Priority == 2 assert primitive.MoveDestination == b'MOVE_SCP ' assert primitive.MessageID == 7 ds = decode(primitive.Identifier, True, True) assert ds.QueryRetrieveLevel == 'PATIENT' assert ds.PatientID == '*' msg = C_MOVE_RSP() for data in [c_move_rsp_cmd, c_move_rsp_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() assert isinstance(primitive, C_MOVE) assert isinstance(primitive.Identifier, BytesIO) assert primitive.AffectedSOPClassUID == UID( '1.2.840.10008.5.1.4.1.1.2') assert primitive.Status == 65280 assert primitive.MessageIDBeingRespondedTo == 5 assert primitive.NumberOfRemainingSuboperations == 3 assert primitive.NumberOfCompletedSuboperations == 1 assert primitive.NumberOfFailedSuboperations == 2 assert primitive.NumberOfWarningSuboperations == 4 ds = decode(primitive.Identifier, True, True) assert ds.QueryRetrieveLevel == 'PATIENT' assert ds.PatientID == '*'
def test_message_to_primitive_c_get(self): """Test converting C_GET_RQ to C_GET primitive.""" msg = C_GET_RQ() for data in [c_get_rq_cmd, c_get_rq_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() self.assertTrue(isinstance(primitive, C_GET)) self.assertTrue(isinstance(primitive.Identifier, BytesIO)) self.assertTrue( primitive.AffectedSOPClassUID == UID('1.2.840.10008.5.1.4.1.1.2')) self.assertTrue(primitive.Priority == 2) self.assertTrue(primitive.MessageID == 7) ds = decode(primitive.Identifier, True, True) self.assertEqual(ds.QueryRetrieveLevel, 'PATIENT') self.assertEqual(ds.PatientID, '*') msg = C_GET_RSP() for data in [c_get_rsp_cmd, c_get_rsp_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() self.assertTrue(isinstance(primitive, C_GET)) self.assertTrue(isinstance(primitive.Identifier, BytesIO)) self.assertTrue( primitive.AffectedSOPClassUID == UID('1.2.840.10008.5.1.4.1.1.2')) self.assertTrue(primitive.Status == 65280) self.assertTrue(primitive.MessageIDBeingRespondedTo == 5) self.assertTrue(primitive.NumberOfRemainingSuboperations == 3) self.assertTrue(primitive.NumberOfCompletedSuboperations == 1) self.assertTrue(primitive.NumberOfFailedSuboperations == 2) self.assertTrue(primitive.NumberOfWarningSuboperations == 4) ds = decode(primitive.Identifier, True, True) self.assertEqual(ds.QueryRetrieveLevel, 'PATIENT') self.assertEqual(ds.PatientID, '*')
def test_message_to_primitive_n_action(self): """Test converting N_ACTION_RQ and _RSP to primitive.""" # N-ACTION-RQ msg = N_ACTION_RQ() for data in [n_action_rq_cmd, n_action_rq_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() assert isinstance(primitive, N_ACTION) assert primitive.RequestedSOPClassUID == UID( '1.2.840.10008.5.1.4.1.1.2') assert primitive.RequestedSOPInstanceUID == UID( '1.2.392.200036.9116.2.6.1.48') assert primitive.MessageID == 7 assert primitive.ActionTypeID == 1 ds = decode(primitive.ActionInformation, True, True) assert ds.PatientName == 'Tube HeNe' assert ds.PatientID == 'Test1101' # N-ACTION-RSP msg = N_ACTION_RSP() for data in [n_action_rsp_cmd, n_action_rsp_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() assert isinstance(primitive, N_ACTION) assert primitive.AffectedSOPClassUID == UID('1.2.4.10') assert primitive.AffectedSOPInstanceUID == UID('1.2.4.5.7.8') assert primitive.MessageIDBeingRespondedTo == 5 assert primitive.ActionTypeID == 1 assert primitive.Status == 0x0000 ds = decode(primitive.ActionReply, True, True) assert ds.PatientName == 'Tube HeNe' assert ds.PatientID == 'Test1101'
def test_message_to_primitive_n_set(self): """Test converting N_SET_RQ and _RSP to primitive.""" # N-SET-RQ msg = N_SET_RQ() for data in [n_set_rq_cmd, n_set_rq_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) primitive = msg.message_to_primitive() assert isinstance(primitive, N_SET) assert primitive.RequestedSOPClassUID == UID( '1.2.840.10008.5.1.4.1.1.2') assert primitive.RequestedSOPInstanceUID == UID( '1.2.392.200036.9116.2.6.1.48') assert primitive.MessageID == 7 ds = decode(primitive.ModificationList, True, True) assert ds.PatientName == 'Tube HeNe' assert ds.PatientID == 'Test1101' # N-SET-RSP msg = N_SET_RSP() for data in [n_set_rsp_cmd, n_set_rsp_ds]: p_data = P_DATA() p_data.presentation_data_value_list.append([0, data]) msg.decode_msg(p_data) msg.decode_msg(p_data) primitive = msg.message_to_primitive() assert isinstance(primitive, N_SET) assert isinstance(primitive.AttributeList, BytesIO) assert primitive.AffectedSOPClassUID == UID('1.2.4.10') assert primitive.AffectedSOPInstanceUID == UID('1.2.4.5.7.8') assert primitive.MessageIDBeingRespondedTo == 5 assert primitive.Status == 0x0000 ds = decode(primitive.AttributeList, True, True) assert ds.PatientName == 'Tube HeNe' assert ds.PatientID == 'Test1101'
def test_assignment(self): """ Check assignment works correctly """ primitive = N_CREATE() # AffectedSOPClassUID primitive.AffectedSOPClassUID = '1.1.1' assert primitive.AffectedSOPClassUID == UID('1.1.1') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPClassUID = UID('1.1.2') assert primitive.AffectedSOPClassUID == UID('1.1.2') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPClassUID = b'1.1.3' assert primitive.AffectedSOPClassUID == UID('1.1.3') assert isinstance(primitive.AffectedSOPClassUID, UID) # AffectedSOPInstanceUID primitive.AffectedSOPInstanceUID = b'1.2.1' assert primitive.AffectedSOPInstanceUID == UID('1.2.1') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPInstanceUID = UID('1.2.2') assert primitive.AffectedSOPInstanceUID == UID('1.2.2') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPInstanceUID = '1.2.3' assert primitive.AffectedSOPInstanceUID == UID('1.2.3') assert isinstance(primitive.AffectedSOPClassUID, UID) # AttributeList ref_ds = Dataset() ref_ds.PatientID = '1234567' primitive.AttributeList = BytesIO(encode(ref_ds, True, True)) ds = decode(primitive.AttributeList, True, True) assert ds.PatientID == '1234567' # MessageID primitive.MessageID = 11 assert 11 == primitive.MessageID # MessageIDBeingRespondedTo primitive.MessageIDBeingRespondedTo = 13 assert 13 == primitive.MessageIDBeingRespondedTo # Status primitive.Status = 0x0000 assert primitive.Status == 0x0000
def decode_msg(self, primitive): """Converts P-DATA primitives into a DIMSEMessage sub-class. Decodes the data from the P-DATA service primitive (which may contain the results of one or more P-DATA-TF PDUs) into the `command_set` and `data_set` attributes. Also sets the `ID` and `encoded_command_set` attributes of the DIMSEMessage sub-class object. Parameters ---------- primitive : pynetdicom3.pdu_primitives.P_DATA The P-DATA service primitive to be decoded into a DIMSE message. Returns ------- bool True when the DIMSE message is completely decoded, False otherwise. """ # Make sure this is a P-DATA primitive if primitive.__class__ != P_DATA or primitive is None: return False for (context_id, data) in primitive.presentation_data_value_list: # The first byte of the P-DATA is the Message Control Header # See PS3.8 Annex E.2 # The standard says that only the significant bits (ie the last # two) should be checked # xxxxxx00 - Message Dataset information, not the last fragment # xxxxxx01 - Command information, not the last fragment # xxxxxx10 - Message Dataset information, the last fragment # xxxxxx11 - Command information, the last fragment ## Compatibility # Python 2 # - data[0] returns length 1 str # - data[:1] returns length 1 str # Python 3 # - data[0] returns int # - data[:1] returns length 1 bytes # So grab str/bytes and convert to int rather than grab # str/int and convert the str to int. The reason for this is # that a type check is twice as expensive as just converting # str/bytes to int control_header_byte = ord(data[:1]) # LOGGER.debug('Control header byte %s', control_header_byte) #print('Control header byte {}'.format(control_header_byte)) # COMMAND SET # P-DATA fragment contains Command Set information # (control_header_byte is xxxxxx01 or xxxxxx11) if control_header_byte & 1: # The command set may be spread out over a number # of fragments and P-DATA primitives and we need to remember # the elements from previous fragments, hence the # encoded_command_set class attribute # This adds all the command set data to the class object self.encoded_command_set.write(data[1:]) # The final command set fragment (xxxxxx11) has been added # so decode the command set if control_header_byte & 2: # Presentation Context ID # Set this now as must only be one final command set # fragment and command set must always be present self.ID = context_id # Command Set is always encoded Implicit VR Little Endian # decode(dataset, is_implicit_VR, is_little_endian) # pylint: disable=attribute-defined-outside-init self.command_set = decode(self.encoded_command_set, True, True) # Determine which DIMSE Message class to use self.__class__ = \ _MESSAGE_CLASS_TYPES[self.command_set.CommandField] # Determine if a Data Set is present by checking for # (0000, 0800) CommandDataSetType US 1. If the value is # 0x0101 no dataset present, otherwise one is. if self.command_set.CommandDataSetType == 0x0101: # By returning True we're indicating that the message # has been completely decoded return True # DATA SET # P-DATA fragment contains Data Set information # (control_header_byte is xxxxxx00 or xxxxxx10) else: # As with the command set, the data set may be spread over # a number of fragments in each P-DATA primitive and a # number of P-DATA primitives. self.data_set.write(data[1:]) # The final data set fragment (xxxxxx10) has been added if control_header_byte & 2 != 0: # By returning True we're indicating that the message # has been completely decoded return True # We return False to indicate that the message isn't yet fully decoded return False
def decode_msg(self, pdata): """Converts P-DATA primitives into a DIMSEMessage sub-class. Decodes the data from the P-DATA service primitive (which may contain the results of one or more P-DATA-TF PDUs) into the `command_set` and `data_set` attributes. Also sets the `ID` and `encoded_command_set` attributes of the DIMSEMessage sub-class object. Parameters ---------- pdata : pynetdicom3.pdu_primitives.P_DATA The P-DATA service primitive to be decoded into a DIMSE message. Returns ------- bool True when complete, False otherwise. """ # Make sure this is a P-DATA primitive if pdata.__class__ != P_DATA or pdata is None: return False for pdv_item in pdata.presentation_data_value_list: # Presentation Context ID self.ID = pdv_item[0] # The first byte of the P-DATA is the Message Control Header # See PS3.8 Annex E.2 # The standard says that only the significant bits (ie the last # two) should be checked # xxxxxx00 - Message Dataset information, not the last fragment # xxxxxx01 - Command information, not the last fragment # xxxxxx10 - Message Dataset information, the last fragment # xxxxxx11 - Command information, the last fragment control_header_byte = pdv_item[1][0] # Python 2 ompatibility if isinstance(control_header_byte, str): control_header_byte = ord(control_header_byte) ## COMMAND SET # P-DATA fragment contains Command Set information # (control_header_byte is xxxxxx01 or xxxxxx11) if control_header_byte & 1: # The command set may be spread out over a number # of fragments and we need to remember the elements # from previous fragments, hence the encoded_command_set # class attribute # This adds all the command set data to the class object self.encoded_command_set.write(pdv_item[1][1:]) # The final command set fragment (xxxxxx11) has been added # so decode the command set if control_header_byte & 2: # Command Set is always encoded Implicit VR Little Endian # decode(dataset, is_implicit_VR, is_little_endian) # pylint: disable=attribute-defined-outside-init self.command_set = decode(self.encoded_command_set, True, True) # Determine which DIMSE Message class to use self.__class__ = \ _MESSAGE_CLASS_TYPES[self.command_set.CommandField] # Determine if a Data Set is present by checking for element # (0000, 0800) CommandDataSetType US 1. If the value is # 0x0101 no dataset present, otherwise one is. if self.command_set.CommandDataSetType == 0x0101: return True ## DATA SET # P-DATA fragment contains Data Set information # (control_header_byte is xxxxxx00 or xxxxxx10) else: # Adds all the dataset data to the class object - still needs to # be decoded, however self.data_set.write(pdv_item[1][1:]) # The final data set fragment (xxxxxx10) has been added if control_header_byte & 2 != 0: return True return False
def test_assignment(self): """Check assignment works correctly""" primitive = N_GET() # AffectedSOPClassUID primitive.AffectedSOPClassUID = '1.1.1' assert primitive.AffectedSOPClassUID == UID('1.1.1') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPClassUID = UID('1.1.2') assert primitive.AffectedSOPClassUID == UID('1.1.2') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPClassUID = b'1.1.3' assert primitive.AffectedSOPClassUID == UID('1.1.3') assert isinstance(primitive.AffectedSOPClassUID, UID) # AffectedSOPInstanceUID primitive.AffectedSOPInstanceUID = b'1.2.1' assert primitive.AffectedSOPInstanceUID == UID('1.2.1') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPInstanceUID = UID('1.2.2') assert primitive.AffectedSOPInstanceUID == UID('1.2.2') assert isinstance(primitive.AffectedSOPClassUID, UID) primitive.AffectedSOPInstanceUID = '1.2.3' assert primitive.AffectedSOPInstanceUID == UID('1.2.3') assert isinstance(primitive.AffectedSOPClassUID, UID) # AttributeList ref_ds = Dataset() ref_ds.PatientID = '1234567' primitive.AttributeList = BytesIO(encode(ref_ds, True, True)) ds = decode(primitive.AttributeList, True, True) assert ds.PatientID == '1234567' # AttributeIdentifierList primitive.AttributeIdentifierList = [ 0x00001000, (0x0000, 0x1000), Tag(0x7fe0, 0x0010) ] assert [Tag(0x0000, 0x1000), Tag(0x0000, 0x1000), Tag(0x7fe0, 0x0010)] == primitive.AttributeIdentifierList primitive.AttributeIdentifierList = [(0x7fe0, 0x0010)] assert [Tag(0x7fe0, 0x0010)] == primitive.AttributeIdentifierList primitive.AttributeIdentifierList = (0x7fe0, 0x0010) assert [Tag(0x7fe0, 0x0010)] == primitive.AttributeIdentifierList elem = DataElement((0x0000, 0x0005), 'AT', [Tag(0x0000, 0x1000)]) assert isinstance(elem.value, MutableSequence) primitive.AttributeIdentifierList = elem.value assert [Tag(0x0000, 0x1000)] == primitive.AttributeIdentifierList # MessageID primitive.MessageID = 11 assert 11 == primitive.MessageID # MessageIDBeingRespondedTo primitive.MessageIDBeingRespondedTo = 13 assert 13 == primitive.MessageIDBeingRespondedTo # RequestedSOPClassUID primitive.RequestedSOPClassUID = '1.1.1' assert primitive.RequestedSOPClassUID == UID('1.1.1') assert isinstance(primitive.RequestedSOPClassUID, UID) primitive.RequestedSOPClassUID = UID('1.1.2') assert primitive.RequestedSOPClassUID == UID('1.1.2') assert isinstance(primitive.RequestedSOPClassUID, UID) primitive.RequestedSOPClassUID = b'1.1.3' assert primitive.RequestedSOPClassUID == UID('1.1.3') assert isinstance(primitive.RequestedSOPClassUID, UID) # RequestedSOPInstanceUID primitive.RequestedSOPInstanceUID = b'1.2.1' assert primitive.RequestedSOPInstanceUID == UID('1.2.1') assert isinstance(primitive.RequestedSOPInstanceUID, UID) primitive.RequestedSOPInstanceUID = UID('1.2.2') assert primitive.RequestedSOPInstanceUID == UID('1.2.2') assert isinstance(primitive.RequestedSOPInstanceUID, UID) primitive.RequestedSOPInstanceUID = '1.2.3' assert primitive.RequestedSOPInstanceUID == UID('1.2.3') assert isinstance(primitive.RequestedSOPInstanceUID, UID) # Status primitive.Status = 0x0000 assert primitive.Status == 0x0000
def test_failure(self): bytestream = BytesIO( b'\x08\x00\x01\x00\x04\x00\x00\x00\x00\x08\x00\x49') with pytest.raises(NotImplementedError): ds = decode(bytestream, False, True) print(ds)