Completed
Push — master ( 5644bc...b87258 )
by Paolo
17s queued 13s
created

image_app.mixins.BioSampleMixin.__can_I()   A

Complexity

Conditions 2

Size

Total Lines 18
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 18
rs 10
c 0
b 0
f 0
cc 2
nop 2
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Fri Jun 28 14:46:39 2019
5
6
@author: Paolo Cozzi <[email protected]>
7
8
Define mixins classes for image_app.models
9
10
"""
11
12
import logging
13
14
from django.db import connections
15
from django.utils import timezone
16
17
from common.constants import STATUSES
18
from common.helpers import format_attribute
19
20
# Get an instance of a logger
21
logger = logging.getLogger(__name__)
22
23
24
# Adding a classmethod to Category if you want to enable truncate
25
# https://books.agiliq.com/projects/django-orm-cookbook/en/latest/truncate.html
26
class BaseMixin(object):
27
    """Base class for UID tables. It implement common stuff for all UID
28
    tables::
29
30
        from image_app.models import BaseMixin
31
32
        class Submission(BaseMixin):
33
            pass
34
35
    """
36
37
    @classmethod
38
    def truncate(cls):
39
        """
40
        Truncate table data and restart indexes from 0::
41
42
            from image_app.models import Submission
43
44
            Submission.truncate()
45
        """
46
47
        # Django.db.connections is a dictionary-like object that allows you
48
        # to retrieve a specific connection using its alias
49
        with connections["default"].cursor() as cursor:
50
            statement = "TRUNCATE TABLE {0} RESTART IDENTITY CASCADE".format(
51
                cls._meta.db_table)
52
            logger.debug(statement)
53
            cursor.execute(statement)
54
55
56
class BioSampleMixin(BaseMixin):
57
    """
58
    Common methods for animal and samples useful in biosample generation
59
    Need to called with data into biosample or animals::
60
61
        from image_app.models import Animal
62
63
        animal = Animal.objects.get(pk=1)
64
        biosample_data = animal.to_biosample()
65
66
    """
67
68
    def __str__(self):
69
        return str(self.name)
70
71
    @property
72
    def person(self):
73
        """Retrieve :py:class:`Person` information from owner relationship"""
74
75
        return self.owner.person
76
77
    @property
78
    def organization(self):
79
        """Return :py:class:`Organization` relationship from related
80
        :py:class:`Submission` object"""
81
82
        return self.name.submission.organization
83
84
    @property
85
    def gene_bank_country(self):
86
        """Return :py:class:`DictCountry` relationship from related
87
        :py:class:`Submission` object"""
88
89
        return self.name.submission.gene_bank_country
90
91
    @property
92
    def gene_bank_name(self):
93
        """Return gene bank name from related :py:class:`Submission` object"""
94
95
        return self.name.submission.gene_bank_name
96
97
    @property
98
    def data_source_id(self):
99
        """Get Data source id (original animal/sample name) from related
100
        :py:class:`Name` object"""
101
102
        return self.name.name
103
104
    @property
105
    def submission(self):
106
        """Get related :py:class:`Submission` object throgh :py:class:`Name`
107
        """
108
        return self.name.submission
109
110
    @property
111
    def specie(self):
112
        raise NotImplementedError(
113
            "You need to define this method in your class")
114
115
    @property
116
    def biosample_id(self):
117
        """Get the biosample_id of an object (need to be submitted and
118
        retrieved sing USI)"""
119
120
        return self.name.biosample_id
121
122
    def get_attributes(self):
123
        """Common attribute definition required from Animal and samples. Need
124
        to be called inside Animal/sample get_atribute method. Keys
125
        is the name in metadata rules
126
127
        Returns:
128
            dict: a dictionary object
129
        """
130
131
        attributes = {}
132
133
        attributes['Data source ID'] = format_attribute(
134
            value=self.data_source_id)
135
136
        attributes['Alternative id'] = format_attribute(
137
            value=self.alternative_id)
138
139
        # HINT: this is a mandatory biosample field: could be removed from
140
        # attributes?
141
        attributes['Description'] = format_attribute(
142
            value=self.description)
143
144
        attributes["Project"] = format_attribute(
145
            value="IMAGE")
146
147
        attributes['Submission title'] = format_attribute(
148
            value=self.submission.title)
149
150
        attributes['Submission description'] = format_attribute(
151
            value=self.submission.description)
152
153
        attributes['Person last name'] = format_attribute(
154
            value=self.owner.last_name)
155
156
        attributes['Person initial'] = format_attribute(
157
            value=self.person.initials)
158
159
        attributes['Person first name'] = format_attribute(
160
            value=self.owner.first_name)
161
162
        attributes['Person email'] = format_attribute(
163
            value="mailto:%s" % (self.owner.email))
164
165
        attributes['Person affiliation'] = format_attribute(
166
            value=self.person.affiliation.name)
167
168
        attributes['Person role'] = self.person.role.format_attribute()
169
170
        attributes['Organization name'] = format_attribute(
171
            value=self.organization.name)
172
173
        attributes['Organization address'] = format_attribute(
174
            value=self.organization.address)
175
176
        attributes['Organization uri'] = format_attribute(
177
            value=self.organization.URI)
178
179
        attributes['Organization country'] = \
180
            self.organization.country.format_attribute()
181
182
        attributes[
183
            'Organization role'] = self.organization.role.format_attribute()
184
185
        # this could be present or not
186
        if self.name.publication:
187
            attributes['Publication DOI'] = format_attribute(
188
                value=self.name.publication.doi)
189
190
        attributes['Gene bank name'] = format_attribute(
191
            value=self.gene_bank_name)
192
193
        attributes[
194
            'Gene bank country'] = self.gene_bank_country.format_attribute()
195
196
        attributes['Data source type'] = format_attribute(
197
            value=self.submission.get_datasource_type_display())
198
199
        attributes['Data source version'] = format_attribute(
200
            value=self.submission.datasource_version)
201
202
        attributes['Species'] = self.specie.format_attribute()
203
204
        return attributes
205
206
    def to_biosample(self, release_date=None):
207
        """
208
        Common stuff to generate a biosample object. Need to be called
209
        inside Animal/Sample to_biosample method
210
211
        Args:
212
            release_date (str): data will no be published before this day
213
                (YYYY-MM-DD)
214
215
        Returns:
216
            dict: a dictionary object
217
        """
218
219
        result = {}
220
221
        # define mandatory fields
222
        result['alias'] = self.biosample_alias
223
        result['title'] = self.name.name
224
225
        # in case of update, I need to provide the old accession in payload
226
        if self.biosample_id and self.biosample_id != '':
227
            result['accession'] = self.biosample_id
228
229
        if release_date:
230
            result['releaseDate'] = release_date
231
232
        else:
233
            now = timezone.now()
234
            result['releaseDate'] = str(now.date())
235
236
        result['taxonId'] = self.specie.taxon_id
237
238
        result['taxon'] = self.specie.label
239
240
        # define optinal fields
241
        if self.description:
242
            result['description'] = self.description
243
244
        # define attributes that will be customized in Animal and sample
245
        result['attributes'] = self.get_attributes()
246
247
        return result
248
249
    def __can_I(self, names):
250
        """
251
        Return True id self.status in statuses
252
253
        Args:
254
            names (list): a list of :py:class:`common.constants.STATUSES`
255
256
        Returns:
257
            bool
258
        """
259
260
        statuses = [x.value[0] for x in STATUSES if x.name in names]
261
262
        if self.submission.status not in statuses:
263
            return True
264
265
        else:
266
            return False
267
268
    def can_edit(self):
269
        """Returns True if I can edit a sample/animal according to submission
270
        status
271
272
        Returns:
273
            bool
274
        """
275
276
        names = ['waiting', 'submitted']
277
278
        return self.__can_I(names)
279
280
    def can_delete(self):
281
        """Returns True if I can delete a sample/animal according to submission
282
        status
283
284
        Returns:
285
            bool
286
        """
287
288
        names = ['waiting', 'submitted']
289
290
        return self.__can_I(names)
291