Passed
Pull Request — master (#30)
by Paolo
01:17
created

common.helpers.construct_validation_message()   A

Complexity

Conditions 1

Size

Total Lines 27
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 27
rs 9.9
c 0
b 0
f 0
cc 1
nop 1
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Wed Mar 27 12:50:16 2019
5
6
@author: Paolo Cozzi <[email protected]>
7
"""
8
9
import logging
10
import websockets
11
import time
12
import json
13
14
from dateutil.relativedelta import relativedelta
15
16
from django.contrib.admin.utils import NestedObjects
17
from django.db import DEFAULT_DB_ALIAS
18
from django.utils.text import capfirst
19
from django.utils.encoding import force_text
20
from validation.helpers import ValidationSummary
21
22
from .constants import YEARS, MONTHS, DAYS
23
24
# Get an instance of a logger
25
logger = logging.getLogger(__name__)
26
27
28
def image_timedelta(t1, t2):
29
    """A function to deal with image time intervals. Returns a number and
30
    time unit"""
31
32
    if t1 is None or t2 is None:
33
        logger.warning("One date is NULL ({0}, {1}) ignoring".format(t2, t1))
34
        return None, YEARS
35
36
    if t2 > t1:
37
        logger.warning("t2>t1 ({0}, {1}) ignoring".format(t2, t1))
38
        return None, YEARS
39
40
    # check for meaningful intervald
41
    if t1.year == 1900 or t2.year == 1900:
42
        logger.warning("Ignoring one date ({0}, {1})".format(t2, t1))
43
        return None, YEARS
44
45
    rdelta = relativedelta(t1, t2)
46
47
    if rdelta.years != 0:
48
        return rdelta.years, YEARS
49
50
    elif rdelta.months != 0:
51
        return rdelta.months, MONTHS
52
53
    else:
54
        return rdelta.days, DAYS
55
56
57
# https://stackoverflow.com/a/39533619/4385116
58
# inspired django.contrib.admin.utils.get_deleted_objects, this function
59
# tries to determine all related objects starting from a provied one
60
# HINT: similar function at https://gist.github.com/nealtodd/4594575
61
def get_deleted_objects(objs, db_alias=DEFAULT_DB_ALIAS):
62
    # NestedObjects is an imporovement of django.db.models.deletion.Collector
63
    collector = NestedObjects(using=db_alias)
64
    collector.collect(objs)
65
66
    def format_callback(obj):
67
        opts = obj._meta
68
        no_edit_link = '%s: %s' % (capfirst(opts.verbose_name),
69
                                   force_text(obj))
70
        return no_edit_link
71
72
    to_delete = collector.nested(format_callback)
73
    protected = [format_callback(obj) for obj in collector.protected]
74
    model_count = {
75
        model._meta.verbose_name_plural:
76
            len(objs) for model, objs in collector.model_objs.items()}
77
78
    return to_delete, model_count, protected
79
80
81
def construct_validation_message(submission):
82
    """
83
    Function will return dict with all the data required to construct
84
    validation message
85
86
    Args:
87
        submission : submission to get data from
88
89
    Returns:
90
        dict: dictionary with all required data for validation message
91
    """
92
    validation_summary = ValidationSummary(submission)
93
    validation_message = dict()
94
95
    # Number of animal and samples
96
    validation_message['animals'] = validation_summary.n_animals
97
    validation_message['samples'] = validation_summary.n_samples
98
99
    # Number of unknow validations
100
    validation_message['animal_unkn'] = validation_summary.n_animal_unknown
101
    validation_message['sample_unkn'] = validation_summary.n_sample_unknown
102
103
    # Number of problem validations
104
    validation_message['animal_issues'] = validation_summary.n_animal_issues
105
    validation_message['sample_issues'] = validation_summary.n_sample_issues
106
107
    return validation_message
108
109
110
async def send_message_to_websocket(message, pk):
111
    """
112
    Function will create websocket object and send message to django-channels
113
    Args:
114
        message (dict): message to send to websocket
115
        pk (str): primary key of submission
116
    """
117
    # Need to have it here as in case with small test data message sent to
118
    # websocket will overcome response from server
119
    time.sleep(3)
120
    async with websockets.connect(
121
            'ws://asgi:8001/image/ws/submissions/{}/'.format(pk)) as websocket:
122
        await websocket.send(json.dumps(message))
123