Completed
Push — master ( 4b6b67...211fa1 )
by Jasper
9s
created

MongoRepository   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 174
rs 8.8
wmc 36

19 Methods

Rating   Name   Duplication   Size   Complexity  
A knows() 0 7 1
A byLocations() 0 3 2
A __init__() 0 7 1
A knowsByLocation() 0 8 1
A byLocation() 0 17 2
A add() 0 7 1
A all() 0 8 2
A updateApproval() 0 3 1
A getSeries() 0 17 2
A knowsSeries() 0 14 2
A update() 0 8 1
A byId() 0 6 2
A latest() 0 3 2
A byParents() 0 4 2
A statistics() 0 13 2
A inflate() 0 7 3
A deflate() 0 8 3
A search() 0 7 3
A inquire() 0 7 3
1
import pymongo, copy, bson
2
from datetime import timedelta
3
from niprov.dependencies import Dependencies
4
5
6
class MongoRepository(object):
7
8
    def __init__(self, dependencies=Dependencies()):
9
        self.config = dependencies.getConfiguration()
10
        self.factory = dependencies.getFileFactory()
11
        self.pictures = dependencies.getPictureCache()
12
        self.listener = dependencies.getListener()
13
        client = pymongo.MongoClient(self.config.database_url)
14
        self.db = client.get_default_database()
15
16
    def byLocation(self, locationString):
17
        """Get the provenance for a file at the given location. 
18
19
        In the case of a dicom series, this returns the provenance for the 
20
        series.
21
22
        Args:
23
            locationString (str): Location of the image file.
24
25
        Returns:
26
            dict: Provenance for one image file.
27
        """
28
        record = self.db.provenance.find_one({'location':locationString})
29
        if record is None:
30
            self.listener.unknownFile(locationString)
31
            return
32
        return self.inflate(record)
33
34
    def byLocations(self, listOfLocations):
35
        records = self.db.provenance.find({'location':{'$in':listOfLocations}})
36
        return [self.inflate(record) for record in records]
37
38
    def knowsByLocation(self, locationString):
39
        """Whether the file at this location has provenance associated with it.
40
41
        Returns:
42
            bool: True if provenance is available for that path.
43
        """
44
        return self.db.provenance.find_one(
45
            {'location':locationString}) is not None
46
47
    def knows(self, image):
48
        """Whether this file has provenance associated with it.
49
50
        Returns:
51
            bool: True if provenance is available for this image.
52
        """
53
        return self.knowsByLocation(image.location.toString())
54
55
    def getSeries(self, image):
56
        """Get the object that carries provenance for the series that the image 
57
        passed is in. 
58
59
        Args:
60
            image (:class:`.DicomFile`): File that is part of a series.
61
62
        Returns:
63
            :class:`.DicomFile`: Image object that caries provenance for 
64
                         the series.
65
        """
66
        seriesUid = image.getSeriesId()
67
        record = self.db.provenance.find_one({'seriesuid':seriesUid})
68
        if record is None:
69
            self.listener.unknownFile('seriesuid: '+str(seriesUid))
70
            return
71
        return self.inflate(record)
72
73
    def knowsSeries(self, image):
74
        """Whether this file is part of a series for which provenance 
75
        is available.
76
77
        Args:
78
            image (:class:`.BaseFile`): File for which the series is sought.
79
80
        Returns:
81
            bool: True if provenance is available for this series.
82
        """
83
        seriesUid = image.getSeriesId()
84
        if seriesUid is None:
85
            return False
86
        return self.db.provenance.find_one({'seriesuid':seriesUid}) is not None
87
88
    def add(self, image):
89
        """Add the provenance for one file to storage.
90
91
        Args:
92
            image (:class:`.BaseFile`): Image file to store.
93
        """
94
        self.db.provenance.insert_one(self.deflate(image))
95
96
    def update(self, image):
97
        """Save changed provenance for this file..
98
99
        Args:
100
            image (:class:`.BaseFile`): Image file that has changed.
101
        """
102
        self.db.provenance.update({'location':image.location.toString()}, 
103
            self.deflate(image))
104
105
    def updateApproval(self, locationString, approvalStatus):
106
        self.db.provenance.update({'location':locationString}, 
107
            {'$set': {'approval': approvalStatus}})
108
109
    def all(self):
110
        """Retrieve all known provenance from storage.
111
112
        Returns:
113
            list: List of provenance for known files.
114
        """
115
        records = self.db.provenance.find()
116
        return [self.inflate(record) for record in records]
117
118
    def latest(self):
119
        records = self.db.provenance.find().sort('added', -1).limit(20)
120
        return [self.inflate(record) for record in records]
121
122
    def statistics(self):
123
        grps = self.db.provenance.aggregate(
124
           [{'$group':
125
                 {
126
                   '_id': None,
127
                   'totalsize': { '$sum': '$size' },
128
                   'count': { '$sum': 1 }
129
                 }
130
            }])
131
        groups = list(grps)
132
        if len(list(groups)) == 0:
133
            return {'count':0}
134
        return list(groups)[0]
135
136
    def byId(self, uid):
137
        record = self.db.provenance.find_one({'id':uid})
138
        if record is None:
139
            self.listener.unknownFile('id: '+str(uid))
140
            return
141
        return self.inflate(record)
142
143
    def byParents(self, listOfParentLocations):
144
        records = self.db.provenance.find({'parents':{
145
            '$in':listOfParentLocations}})
146
        return [self.inflate(record) for record in records]
147
148
    def inquire(self, query):
149
        field = query.getFields()[0]
150
        if field.all:
151
            records = self.db.provenance.distinct(field.name)
152
        else:
153
            records = self.db.provenance.find({field.name:field.value})
154
        return [self.inflate(record) for record in records]
155
156
    def search(self, text):
157
        searchfields = ['location','user','subject','project','protocol',
158
                  'transformation','technique','modality']
159
        indexspec = [(field, pymongo.TEXT) for field in searchfields]
160
        self.db.provenance.create_index(indexspec)
161
        records = self.db.provenance.find({'$text':{'$search': text}})
162
        return [self.inflate(record) for record in records]
163
164
    def deflate(self, img):
165
        record = copy.deepcopy(img.provenance)
166
        if 'duration' in record:
167
            record['duration'] = record['duration'].total_seconds()
168
        snapshotData = self.pictures.getBytes(for_=img)
169
        if snapshotData:
170
            record['_snapshot-data'] = bson.Binary(snapshotData)
171
        return record
172
173
    def inflate(self, record):
174
        if 'duration' in record:
175
            record['duration'] = timedelta(seconds=record['duration'])
176
        img = self.factory.fromProvenance(record)
177
        if '_snapshot-data' in record:
178
            self.pictures.keep(record['_snapshot-data'], for_=img)
179
        return img
180
181