Example #1
0
    def test_bad_instance_none(self):
        """Test that instances with bad data aren't added."""
        keywords = [
            ('PatientID', 16),
            ('PatientName', 64),
            ('StudyInstanceUID', 64),
            ('StudyDate', 8),
            ('StudyTime', 14),
            ('AccessionNumber', 16),
            ('StudyID', 16),
            ('SeriesInstanceUID', 64),
            ('Modality', 16),
            #('SeriesNumber', None),
            ('SOPInstanceUID', 64),
            #('InstanceNumber', None),
        ]
        ds = Dataset()
        ds.PatientID = None
        ds.StudyInstanceUID = None
        ds.SeriesInstanceUID = None
        ds.SOPInstanceUID = None
        with pytest.raises(IntegrityError):
            db.add_instance(ds, self.session)

        self.session.rollback()

        assert not self.session.query(db.Instance).all()
Example #2
0
    def setup(self):
        """Run prior to each test"""
        engine = db.create('sqlite:///:memory:')
        pydicom.config.use_none_as_empty_text_VR_value = True

        self.session = sessionmaker(bind=engine)()
        for fname in DATASETS:
            fpath = os.path.join(DATA_DIR, fname)
            ds = dcmread(fpath)
            db.add_instance(ds, self.session)
Example #3
0
    def test_add_instance(self):
        """Test adding to the instance database."""
        fpath = os.path.join(DATA_DIR, 'CTImageStorage.dcm')
        ds = dcmread(fpath)
        db.add_instance(ds, self.session)

        obj = self.session.query(db.Instance).all()
        assert 1 == len(obj)
        for kk, vv in DATASETS['CTImageStorage.dcm'].items():
            assert vv == getattr(obj[0], kk)
Example #4
0
    def test_instance_exists(self):
        """Test that adding already existing instance updates it."""
        db.add_instance(self.minimal, self.session)

        result = self.session.query(db.Instance).all()
        assert 1 == len(result)
        assert None == result[0].modality

        self.minimal.Modality = 'CT'

        db.add_instance(self.minimal, self.session)
        result = self.session.query(db.Instance).all()
        assert 1 == len(result)
        assert 'CT' == result[0].modality
Example #5
0
    def setup(self):
        """Run prior to each test"""
        engine = db.create('sqlite:///:memory:')

        pydicom.config.use_none_as_empty_text_VR_value = True

        self.session = sessionmaker(bind=engine)()
        ds = Dataset()
        ds.PatientID = '1234'
        ds.StudyInstanceUID = '1.2'
        ds.SeriesInstanceUID = '1.2.3'
        ds.SOPInstanceUID = '1.2.3.4'
        db.add_instance(ds, self.session)

        self.minimal = ds
Example #6
0
    def test_add_multiple_instances(self):
        """Test adding multiple data to the instance database."""
        for fname in DATASETS:
            fpath = os.path.join(DATA_DIR, fname)
            ds = dcmread(fpath)
            db.add_instance(ds, self.session)

        obj = self.session.query(db.Instance).all()
        assert 5 == len(obj)
        obj = self.session.query(db.Instance, db.Instance.patient_name).all()
        names = [val[1] for val in obj]
        assert 'CompressedSamples^CT1' in names
        assert 'CompressedSamples^MR1' in names
        assert 'ANON^A^B^C^D' in names
        assert '^^^^' in names
Example #7
0
    def test_add_minimal(self):
        """Test adding a minimal dataset."""
        db.add_instance(self.minimal, self.session)

        obj = self.session.query(db.Instance).all()
        assert 1 == len(obj)
        assert '1234' == obj[0].patient_id
        assert '1.2' == obj[0].study_instance_uid
        assert '1.2.3' == obj[0].series_instance_uid
        assert '1.2.3.4' == obj[0].sop_instance_uid

        rest = [
            'patient_name', 'study_date', 'study_time', 'accession_number',
            'study_id', 'modality', 'series_number', 'instance_number',
        ]
        for attr in rest:
            assert getattr(obj[0], attr) is None
Example #8
0
    def test_bad_instance(self):
        """Test that instances with bad data aren't added."""
        keywords = [
            ('PatientID', 16),
            ('PatientName', 64),
            ('StudyInstanceUID', 64),
            ('StudyDate', 8),
            ('StudyTime', 14),
            ('AccessionNumber', 16),
            ('StudyID', 16),
            ('SeriesInstanceUID', 64),
            ('Modality', 16),
            #('SeriesNumber', None),
            ('SOPInstanceUID', 64),
            #('InstanceNumber', None),
        ]
        ds = self.minimal[:]
        for kw, max_len in keywords:
            setattr(ds, kw, 'a' * (max_len + 1))
            with pytest.raises(AssertionError):
                db.add_instance(ds, self.session)

        assert not self.session.query(db.Instance).all()
Example #9
0
    def test_add_minimal(self):
        """Test adding a minimal dataset."""
        db.add_instance(self.minimal, self.session)

        obj = self.session.query(db.Instance).all()
        assert 1 == len(obj)
        assert "1234" == obj[0].patient_id
        assert "1.2" == obj[0].study_instance_uid
        assert "1.2.3" == obj[0].series_instance_uid
        assert "1.2.3.4" == obj[0].sop_instance_uid

        rest = [
            "patient_name",
            "study_date",
            "study_time",
            "accession_number",
            "study_id",
            "modality",
            "series_number",
            "instance_number",
        ]
        for attr in rest:
            assert getattr(obj[0], attr) is None
Example #10
0
def handle_store(event, storage_dir, db_path, cli_config, logger):
    """Handler for evt.EVT_C_STORE.

    Parameters
    ----------
    event : pynetdicom.events.Event
        The C-STORE request :class:`~pynetdicom.events.Event`.
    storage_dir : str
        The path to the directory where instances will be stored.
    db_path : str
        The database path to use with create_engine().
    cli_config : dict
        A :class:`dict` containing configuration settings passed via CLI.
    logger : logging.Logger
        The application's logger.

    Returns
    -------
    int or pydicom.dataset.Dataset
        The C-STORE response's *Status*. If the storage operation is successful
        but the dataset couldn't be added to the database then the *Status*
        will still be ``0x0000`` (Success).
    """
    requestor = event.assoc.requestor
    timestamp = event.timestamp.strftime("%Y-%m-%d %H:%M:%S")
    addr, port = requestor.address, requestor.port
    logger.info(f"Received C-STORE request from {addr}:{port} at {timestamp}")

    try:
        ds = event.dataset
        # Remove any Group 0x0002 elements that may have been included
        ds = ds[0x00030000:]
        sop_instance = ds.SOPInstanceUID
    except Exception as exc:
        logger.error("Unable to decode the dataset")
        logger.exception(exc)
        # Unable to decode dataset
        return 0xC210

    # Add the file meta information elements - must be before adding to DB
    ds.file_meta = event.file_meta

    logger.info(f"SOP Instance UID '{sop_instance}'")

    # Try and add the instance to the database
    #   If we fail then don't even try to store
    fpath = os.path.join(storage_dir, sop_instance)
    db_dir = os.path.dirname(db_path)

    if os.path.exists(fpath):
        logger.warning(
            'Instance already exists in storage directory, overwriting')

    try:
        ds.save_as(fpath, write_like_original=False)
    except Exception as exc:
        logger.error('Failed writing instance to storage directory')
        logger.exception(exc)
        # Failed - Out of Resources
        return 0xA700

    logger.info("Instance written to storage directory")

    # Dataset successfully written, try to add to/update database
    engine = create_engine(db_path)
    with engine.connect() as conn:
        Session = sessionmaker(bind=engine)
        session = Session()

        try:
            # Path is relative to the database file
            matches = session.query(Instance).filter(
                Instance.sop_instance_uid == ds.SOPInstanceUID).all()
            add_instance(ds, session, os.path.abspath(fpath))
            if not matches:
                logger.info("Instance added to database")
            else:
                logger.info("Database entry for instance updated")
        except Exception as exc:
            session.rollback()
            logger.error('Unable to add instance to the database')
            logger.exception(exc)
        finally:
            session.close()

    return 0x0000