Blame view

src/routine_manager/RequestSerializer.py 7.24 KB
ddf59dd4   haribo   Remaniement :
1
from common.models import *
eea995c9   haribo   Date: 16/06/2016
2
3
4
import xml.etree.ElementTree as ET
import sys
from xml.dom import minidom
3dbda6a0   haribo   Date: 17/06/2016
5
6
7
from .validators import check_plan_validity
import re
from decimal import Decimal
eea995c9   haribo   Date: 16/06/2016
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

def prettify(elem):
    """
        :returns : A pretty-printed XML string for the Element elem 
    """
    rough_string = ET.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="    ")

class RequestSerializer():
    """
        Serializes and unserializes a request, with all children (sequences, albums and plans)
        Format : XML
        Only serializes the wanted fields
        
        Entry point(s) :
            - serialize
    """

    def serialize(self, req, file_name):
        """
            Serializes the request into the given file
        """
        request = ET.Element("request", name=req.name, scientific_program=req.scientific_program.name,
                             target_type=req.target_type)
        for seq in req.sequences.all():
            sequence = ET.SubElement(request, "sequence", name=seq.name, target_coords=seq.target_coords,
e5189e4f   haribo   Date: 20/06/2016
35
36
                                     jd1=str(seq.jd1), jd2=str(seq.jd2))
            sequence.set("duration", str(seq.duration * 86400))
eea995c9   haribo   Date: 16/06/2016
37
38
39
            for alb in seq.albums.all():
                album = ET.SubElement(sequence, "album", name=alb.name, detector=alb.detector.device.name)
                for plan in alb.plans.all():
e5189e4f   haribo   Date: 20/06/2016
40
41
                    pl = ET.SubElement(album, "plan", name=plan.name, filter=plan.filter.device.name, nb_images=str(plan.nb_images))
                    pl.set("duration", str(plan.duration * 86400))
eea995c9   haribo   Date: 16/06/2016
42
43
44
45

        with open(file_name, "w") as file:
            file.write(prettify(request))

3dbda6a0   haribo   Date: 17/06/2016
46
    def unserialize(self, xml_data, pyros_user):
eea995c9   haribo   Date: 16/06/2016
47
48
49
50
51
52
        """
            Unserializes the request read into file_name
            Throws exceptions in case of invalid file or values
            
            Directly saves the objects in DB
            The request still need to be submitted afterward !
3dbda6a0   haribo   Date: 17/06/2016
53
54
            
            :returns : "" (empty string) in case of success, error message (string) instead
eea995c9   haribo   Date: 16/06/2016
55
        """
3dbda6a0   haribo   Date: 17/06/2016
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

        try:
            root = ET.fromstring(xml_data)
        except ET.ParseError as E:
            return "Invalid file : " + str(E)

        self.pyros_user = pyros_user
        self.request = None

        """ self.sequences will be a [(seq, album_list), ...], and same thing for album """
        self.sequences = []
        ret = self.unserialize_request(root)
        if ret != "":
            return ret

        self.request.save()
        for sequence, albums in self.sequences:
            sequence.request = self.request
            sequence.save()
            for album, plans in albums:
                album.sequence = sequence
                album.save()
                for plan in plans:
                    plan.album = album
                    plan.save()
                    check_plan_validity(plan)

        return ""

    def unserialize_request(self, request):
9b5bad52   haribo   Commented all the...
86
87
88
89
        '''
            Receives an xml.etree request and unserialize it 
        '''

3dbda6a0   haribo   Date: 17/06/2016
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
        if request.tag != "request":
            return "Main object should be a request (found %s instead)" % (request.tag,)
        possible_attribs = ["name", "scientific_program", "target_type"]

        self.request = Request(pyros_user=self.pyros_user, is_alert=False, complete=False, submitted=False)

        for name, value in request.attrib.items():
            if name not in possible_attribs:
                return "Unknown attribute %s in request" % (name,)
            if name == "scientific_program":
                try:
                    sp = ScientificProgram.objects.get(name=value)
                    self.request.scientific_program = sp
                except Exception as E:
                    print(str(E))
                    return "Invalid scientific program %s" % (value,)
            else:
                self.request.__dict__[name] = value

        for sequence in request:
            ret = self.unserialize_sequence(sequence)
            if ret != "":
                return ret
        return ""

    def unserialize_sequence(self, sequence):
        if sequence.tag != "sequence":
            return "A request can only have 'sequence' children (found %s instead)" % (sequence.tag,)
        possible_attribs = ["name", "target_coords", "jd1", "jd2", "duration"]

        seq = Sequence(request=self.request, status=Sequence.INCOMPLETE)

        for name, value in sequence.attrib.items():
            if name not in possible_attribs:
                return "Unknown attribute %s in sequence" % (name,)
            if name == "name":
                seq.name = value
            elif name == "target_coords":
                seq.target_coords = value
            elif name == "jd1":
                seq.jd1 = Decimal(value)
            elif name == "jd2":
                seq.jd2 = Decimal(value)
            elif name == "duration":
e5189e4f   haribo   Date: 20/06/2016
134
                seq.duration = Decimal(value) / 86400
3dbda6a0   haribo   Date: 17/06/2016
135

5d61cbfe   haribo   Just adding / rem...
136
        # TODO: faire des checks ?? j'imagine
3dbda6a0   haribo   Date: 17/06/2016
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
        album_list = []
        self.sequences.append((seq, album_list))

        for album in sequence:
            ret = self.unserialize_album(album, seq, album_list)
            if ret != "":
                return ret
        return ""

    def unserialize_album(self, album, sequence, album_list):
        if album.tag != "album":
            return "A sequence can only have 'album' children (found %s instead)" % (album.tag,)
        possible_attribs = ["name", "detector"]

        alb = Album(sequence=sequence)

        for name, value in album.attrib.items():
            if name not in possible_attribs:
                return "Unknown attribute %s in album" % (name,)
            if name == "detector":
                try:
                    detector = Detector.objects.get(device__name=value)
                    alb.detector = detector
                except Exception as E:
                    print(str(E))
                    return "Invalid detector %s" % (value,)
            elif name == "name":
                alb.name = value
        plan_list = []
        album_list.append((alb, plan_list))

        for plan in album:
            ret = self.unserialize_plan(plan, alb, plan_list)
            if ret != "":
                return ret
        return ""


    def unserialize_plan(self, plan, album, plan_list):
        if plan.tag != "plan":
            return "An album can only have 'plan' children (found %s instead)" % (plan.tag,)
        possible_attribs = ["name", "filter", "duration", "nb_images"]

        pl = Plan(album=album)

        for name, value in plan.attrib.items():
            if name not in possible_attribs:
                return "Unknown attribute %s in plan" % (name,)
            if name == "filter":
                try:
                    filter = Filter.objects.get(device__name=value)
                    pl.filter = filter
                except Exception as E:
                    return "Invalid filter %s" % (value,)
            elif name == "name":
                pl.name = value
            elif name == "duration":
e5189e4f   haribo   Date: 20/06/2016
194
                pl.duration = Decimal(value) / 86400
3dbda6a0   haribo   Date: 17/06/2016
195
196
197
            elif name == "nb_images":
                pl.nb_images = int(value)

5d61cbfe   haribo   Just adding / rem...
198
        # TODO: quelques checks ...
3dbda6a0   haribo   Date: 17/06/2016
199
200
201

        plan_list.append(pl)
        return ""