Blame view

src/core/pyros_django/seq_submit/functions.py 24.2 KB
eefbbbd2   Etienne Pallier   Model splitting g...
1
# Standard import
ad3b297c   Alexis Koralewski   add pagination to...
2
import ast
ad3b297c   Alexis Koralewski   add pagination to...
3
4
import datetime
import os, yaml
13b26571   Alexis Koralewski   Add night_id to s...
5
import pickle
eefbbbd2   Etienne Pallier   Model splitting g...
6
# Django imports
13b26571   Alexis Koralewski   Add night_id to s...
7
from django.forms.models import model_to_dict
b95a693f   Alexis Koralewski   restructuration d...
8
9
from user_mgmt.models import PyrosUser, ScientificProgram, Period
from seq_submit.models import Sequence, Album, Plan
eefbbbd2   Etienne Pallier   Model splitting g...
10
from .forms import SequenceForm, PlanForm   #, AlbumForm
8a9bdc27   Alexis Koralewski   add transaction a...
11
from django.db import IntegrityError, transaction
eefbbbd2   Etienne Pallier   Model splitting g...
12
# Project imports
b95a693f   Alexis Koralewski   restructuration d...
13
from src.core.pyros_django.obs_config.obsconfig_class import OBSConfig
13b26571   Alexis Koralewski   Add night_id to s...
14
from django.http import HttpRequest
23a61124   Alexis Koralewski   Change obsconfig ...
15
from dashboard.config_pyros import ConfigPyros
545ecb30   Alexis Koralewski   Add ephem to pick...
16
17
# guitastro import
import vendor.guitastro.src.guitastro as guitastro 
793d0190   Alexis Koralewski   rework routine_ma...
18
#from silk.profiling.profiler import silk_profile
eefbbbd2   Etienne Pallier   Model splitting g...
19

5c709a6e   Alexis Koralewski   Add ephemeris cal...
20
21
import numpy

793d0190   Alexis Koralewski   rework routine_ma...
22
#@silk_profile(name="check_sequence_file")
8a9bdc27   Alexis Koralewski   add transaction a...
23
@transaction.atomic
13b26571   Alexis Koralewski   Add night_id to s...
24
def check_sequence_file_validity_and_save(yaml_content: dict, request: HttpRequest):
1e252185   Etienne Pallier   petites optimisat...
25
26
    ''' Create a sequence in DB from the uploaded sequence (yaml_content) '''

1e252185   Etienne Pallier   petites optimisat...
27
    # Create a sequence seq object (from yaml_content) to be saved in DB
ad3b297c   Alexis Koralewski   add pagination to...
28
29
    seq = Sequence.objects.create()
    seq.pyros_user = PyrosUser.objects.get(id=request.user.id)
1e252185   Etienne Pallier   petites optimisat...
30
31
    
    # Get the unit config
ad3b297c   Alexis Koralewski   add pagination to...
32
    unit_name = os.environ["unit_name"]
793d0190   Alexis Koralewski   rework routine_ma...
33
    #with silk_profile(name="init obsconfig"):
ad3b297c   Alexis Koralewski   add pagination to...
34
    config = OBSConfig(os.environ["PATH_TO_OBSCONF_FILE"], unit_name)
ad3b297c   Alexis Koralewski   add pagination to...
35
36
37
38
    result = {
        "succeed": True,
        "errors": [],
    }
793d0190   Alexis Koralewski   rework routine_ma...
39
40
41
42
    # Get boolean to simplified to know if the file is written in simplified mode (i.e. : Each field of the form is directly associated to its value)
    is_simplified = yaml_content.get("simplified", False)
    # Get scientific programs for the user who is submitting the sequence file
    user_sp = request.user.get_scientific_programs()
8a9bdc27   Alexis Koralewski   add transaction a...
43

793d0190   Alexis Koralewski   rework routine_ma...
44
    process_sequence(yaml_content, seq, config, is_simplified, result, user_sp)
793d0190   Alexis Koralewski   rework routine_ma...
45
    process_albums(yaml_content, result, config, seq, is_simplified)
8a9bdc27   Alexis Koralewski   add transaction a...
46

1e252185   Etienne Pallier   petites optimisat...
47
        
ea36dc1d   Etienne Pallier   2e petit changeme...
48
49
50
51
52
    # optim possible ?
    #[ process_plans(a["Album"].get("Plans")) for a in albums_from_file ]
    # Puis écrire la fonction process_plans()

    # For each Album a (in file)
1e252185   Etienne Pallier   petites optimisat...
53
54
    # Tu itères 2 fois sur albums_from_file, y aurait pas moyen d'iterer 1 seule fois dessus ?
    #for album in yaml_content["sequence"]["ALBUMS"]:
13b26571   Alexis Koralewski   Add night_id to s...
55
56
57
58
    """
    # Old


1e252185   Etienne Pallier   petites optimisat...
59
60
    for album in albums_from_file:

ad3b297c   Alexis Koralewski   add pagination to...
61
62
        album = album["Album"]
        plans = album.get("Plans")
13b26571   Alexis Koralewski   Add night_id to s...
63
        # If no plan has been defined
ad3b297c   Alexis Koralewski   add pagination to...
64
65
        if plans == None:
            result["errors"].append(f"Album {album['name']} has no plans. Please add at least one plan")
059447d3   Etienne Pallier   petit changement ...
66
67
            # pour eviter le else (plus lisible)
            continue
13b26571   Alexis Koralewski   Add night_id to s...
68
69
        plans = [a["Album"].get("Plans") for a in albums_from_file]
        process_plans(plans, result, is_simplified, config, album, seq)
ea36dc1d   Etienne Pallier   2e petit changeme...
70
        # For each plan p (in album a)
059447d3   Etienne Pallier   petit changement ...
71
        for plan in plans:
13b26571   Alexis Koralewski   Add night_id to s...
72
            new_plan_object = Plan.objects.create(album=Album.objects.get(name=album["name"], sequence=seq), complete=True)
059447d3   Etienne Pallier   petit changement ...
73
74
75
            new_plan_object.config_attributes = {}
            plan = plan["Plan"]
            config_attributes = {}
13b26571   Alexis Koralewski   Add night_id to s...
76
            plan_form = PlanForm(data_from_config=config.getEditableChannelAttributes(config.unit_name,list(config.get_channels(config.unit_name).keys())[0]),edited_plan=None)
ea36dc1d   Etienne Pallier   2e petit changeme...
77
            # Process each plan field
059447d3   Etienne Pallier   petit changement ...
78
79
80
81
82
83
84
85
86
87
            for field in plan_form.fields:
                plan_field = plan[field]
                '''
                min_value = None
                max_value = None
                value_type = None
                '''
                min_value = max_value = value_type = None
                if field not in plan.keys():
                    result["errors"].append(f"Missing field : '{field}' for plan {plans.index(plan)}")
ea36dc1d   Etienne Pallier   2e petit changeme...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
                    continue
                # TODO : ajouter max_value, min_value, suppression plan et album si invalides
                if not is_simplified:
                    if plan_field.get("value_type"):
                        value_type = plan_field["value_type"]
                        if type(plan_field["value"]) == str and ast.literal_eval(plan_field["value"]) != value_type:
                            result["errors"].append(f"Field {field} value doesn't correspond to the assigned type (type required : {value_type})")
                    if plan_field.get("min_value"):
                        min_value = plan_field["min_value"]
                        if type(min_value) == str:
                            min_value = ast.literal_eval(min_value)
                        '''
                        if type(plan_field["min_value"]) == str:
                            min_value = ast.literal_eval(plan_field["min_value"])
                        else:
059447d3   Etienne Pallier   petit changement ...
103
                            min_value = plan_field["min_value"]
059447d3   Etienne Pallier   petit changement ...
104
                        '''
ea36dc1d   Etienne Pallier   2e petit changeme...
105
106
107
108
109
110
111
                    if plan_field.get("max_value"):
                        max_value = plan_field["max_value"]
                        if type(max_value) == str:
                            max_value = ast.literal_eval(max_value)
                        '''
                        if type(plan_field.get("max_value")) == str:
                            max_value = ast.literal_eval(plan_field["max_value"])
ad3b297c   Alexis Koralewski   add pagination to...
112
                        else:
ea36dc1d   Etienne Pallier   2e petit changeme...
113
                            max_value = plan_field["max_value"]
059447d3   Etienne Pallier   petit changement ...
114
                        '''
ea36dc1d   Etienne Pallier   2e petit changeme...
115
116
117
118
119
                if field == "nb_images":
                    new_plan_object.__dict__[field] = plan_field if is_simplified else plan_field["value"]
                    '''
                    if is_simplified:
                        new_plan_object.__dict__[field] = plan_field    
059447d3   Etienne Pallier   petit changement ...
120
                    else:
ea36dc1d   Etienne Pallier   2e petit changeme...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
                        new_plan_object.__dict__[field] = plan_field["value"]
                    '''
                else:
                    # shortcut possible ?
                    #new_plan_object_field = new_plan_object.config_attributes[field]
                    if is_simplified:
                        new_plan_object.config_attributes[field] = plan_field
                    else:
                        if plan_field.get("values"):
                            index_value = plan_field["value"]
                            values =  plan_field["values"]
                            if index_value < 0 or index_value > len(plan_field["values"]):
                                result["errors"].append(f"Value of Plan field '{field}' isn't valid, index out of bounds ({index_value} > {len(values)})")
                                index_value = 0
                            value = plan_field["values"][index_value]
                            try:
                                # linked values
                                splitted_values = value.split(";")
                                config_attributes[field] = {}
                                for splitted_value in splitted_values:
                                    subkey,subvalue = splitted_value.split(":")
                                    config_attributes[field][subkey] = ast.literal_eval(subvalue)
                            # vaudrait mieux préciser l'exception ici
                            except:
                                # Do nothing, normal string
                                config_attributes[field] = ast.literal_eval(value)
                            new_plan_object.config_attributes[field] = config_attributes[field]
059447d3   Etienne Pallier   petit changement ...
148
                        else:
ea36dc1d   Etienne Pallier   2e petit changeme...
149
150
151
152
153
154
155
                            if max_value and min_value:
                                if plan_field["value"] > max_value:
                                    result["errors"].append(f"Plan field {field} doesn't respect max value")
                                if plan_field["value"] < min_value:
                                    result["errors"].append(f"Plan field {field} doesn't respect min value")
                            new_plan_object.config_attributes[field] = plan_field["value"]
            # end foreach plan field
059447d3   Etienne Pallier   petit changement ...
156
157
158
            new_plan_object.save()
        # end foreach plan
    # end foreach album
13b26571   Alexis Koralewski   Add night_id to s...
159
    """
1e252185   Etienne Pallier   petites optimisat...
160

ad3b297c   Alexis Koralewski   add pagination to...
161
162
    seq.status = Sequence.TOBEPLANNED
    seq.complete = True
98621b46   Alexis Koralewski   add DRF, pyros ap...
163
164
165
166
    period = Period.objects.exploitation_period()
    if Period.objects.next_period() != None and Period.objects.next_period().start_date < seq.start_date.date():
        period = Period.objects.next_period()
    seq.period = period
545ecb30   Alexis Koralewski   Add ephem to pick...
167
168
169
170
171
    fn = guitastro.FileNames()
    home = config.getHome()
    guitastro_home = guitastro.Home(home)
    fn.longitude = guitastro_home.longitude
    seq.night_id = fn.get_night(seq.start_date.isoformat()[:19])
4faed281   Alexis Koralewski   Catch integretyer...
172
173
174
175
    try:
        seq.save()
    except IntegrityError as e:
        result["errors"].append(str(e))
5c709a6e   Alexis Koralewski   Add ephemeris cal...
176
    if len(result["errors"]) > 0:
ad3b297c   Alexis Koralewski   add pagination to...
177
178
        result["succeed"] = False
        seq.delete()
98621b46   Alexis Koralewski   add DRF, pyros ap...
179
180
    else:
        result["sequence_id"] = seq.id
ad3b297c   Alexis Koralewski   add pagination to...
181
182
    return result

793d0190   Alexis Koralewski   rework routine_ma...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
def process_albums(yaml_content, result, config, seq, is_simplified):
    # Create ALBUMS
    albums_from_file = yaml_content["sequence"]["ALBUMS"] 
    chosen_layout = seq.config_attributes["layout"]
    if type(chosen_layout) == int:
        #with silk_profile(name="Get layout from config"):
        layouts = config.get_layouts(config.unit_name)["layouts"]
        chosen_layout = list(layouts)[chosen_layout]
    # Get album of the selected layout
    #with silk_profile(name="Get album of layout from config"):
    layout_albums = config.getLayoutByName(unit_name=config.unit_name, name_of_layout=chosen_layout)["ALBUMS"]
    
    # check if we have all the albums of that layout described in the sequence file
    #with silk_profile(name="Iterate on each album & plan (create)"):
    if len(layout_albums) == len(albums_from_file):
        for album in albums_from_file:
            album = album["Album"]
            if album["name"] not in layout_albums:
5c709a6e   Alexis Koralewski   Add ephemeris cal...
201
                result["errors"].append(f"Album {album['name']} is not in the chosen layout. The available albums on this layout are : {layout_albums}")
793d0190   Alexis Koralewski   rework routine_ma...
202
203
204
205
206
207
208
209
210
            else:
                # Create album 
                Album.objects.create(name=album["name"], sequence=seq, complete=True)
            # Create plan for that album
            plans = album.get("Plans")
            process_plans(plans, result, is_simplified, config, album, seq)
    else:
        result["errors"].append(f"The number of albums doesn't correspond to the chosen layout")

13b26571   Alexis Koralewski   Add night_id to s...
211

793d0190   Alexis Koralewski   rework routine_ma...
212
#@silk_profile(name="process_plans")
13b26571   Alexis Koralewski   Add night_id to s...
213
214
215
216
217
218
def process_plans(plans: dict, result: dict, is_simplified: bool, config: OBSConfig, album: dict, seq: dict):
    if plans == None:
        result["errors"].append(f"Album {album['name']} has no plans. Please add at least one plan")
        # exit function
        return None
    for plan in plans:
793d0190   Alexis Koralewski   rework routine_ma...
219
220
        #new_plan_object = Plan.objects.create(album=Album.objects.get(name=album["name"], sequence=seq), complete=True)
        #new_plan_object.config_attributes = {}
13b26571   Alexis Koralewski   Add night_id to s...
221
        plan = plan["Plan"]
793d0190   Alexis Koralewski   rework routine_ma...
222
        nb_images = 0
13b26571   Alexis Koralewski   Add night_id to s...
223
        config_attributes = {}
793d0190   Alexis Koralewski   rework routine_ma...
224
        #with silk_profile(name="Create plan form"):
13b26571   Alexis Koralewski   Add night_id to s...
225
226
        plan_form = PlanForm(data_from_config=config.getEditableChannelAttributes(config.unit_name, list(config.get_channels(config.unit_name).keys())[0]), edited_plan=None)
        # Process each plan field
793d0190   Alexis Koralewski   rework routine_ma...
227
        #with silk_profile(name="iterate on plan fields"):
13b26571   Alexis Koralewski   Add night_id to s...
228
229
230
231
232
233
234
        for field in plan_form.fields:
            plan_field = plan[field]
            '''
            min_value = None
            max_value = None
            value_type = None
            '''
13b26571   Alexis Koralewski   Add night_id to s...
235
            if field == "nb_images":
793d0190   Alexis Koralewski   rework routine_ma...
236
                nb_images = plan_field if is_simplified else plan_field["value"]
13b26571   Alexis Koralewski   Add night_id to s...
237
            else:
793d0190   Alexis Koralewski   rework routine_ma...
238
                process_plan_field(result, config_attributes, plan_field, field, plans, plan, is_simplified)                    
13b26571   Alexis Koralewski   Add night_id to s...
239
        # end foreach plan field
5c709a6e   Alexis Koralewski   Add ephemeris cal...
240
241
242
243
        try:
            Plan.objects.create(album=Album.objects.get(name=album["name"], sequence=seq), complete=True, nb_images=nb_images, config_attributes=config_attributes)
        except Album.DoesNotExist:
            result["errors"].append(f"Album {album['name']} not appearing in obsconfig. Please refer to the observatory configuration to set a valid album name. ")
793d0190   Alexis Koralewski   rework routine_ma...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
def process_plan_field(result, config_attributes, plan_field, field, plans, plan, is_simplified):

    
    if field not in plan.keys():
        result["errors"].append(f"Missing field : '{field}' for plan {plans.index(plan)}")
        # exit function
        return None
    if is_simplified:
        #new_plan_object.config_attributes[field] = plan_field
        config_attributes[field] = plan_field
    else:
        value_type, min_value, max_value = prepare_check_plan_field_value(plan_field, field, result)
        check_and_set_plan_field_value(config_attributes, plan_field, field, result, value_type, min_value, max_value)

        
def check_and_set_plan_field_value(config_attributes, plan_field, field, result, value_type, min_value, max_value):
    # if the value is a index of a list, get the value from this index
    if plan_field.get("values"):
        index_value = plan_field["value"]
        values =  plan_field["values"]
        if index_value < 0 or index_value > len(plan_field["values"]):
            result["errors"].append(f"Value of Plan field '{field}' isn't valid, index out of bounds ({index_value} > {len(values)})")
            index_value = 0
        value = plan_field["values"][index_value]
        try:
            # linked values
            splitted_values = value.split(";")
            config_attributes[field] = {}
            for splitted_value in splitted_values:
                subkey,subvalue = splitted_value.split(":")
                config_attributes[field][subkey] = ast.literal_eval(subvalue)
        # vaudrait mieux préciser l'exception ici
        except ValueError:
            # Do nothing, normal string
            config_attributes[field] = ast.literal_eval(value)
        #new_plan_object.config_attributes[field] = config_attributes[field]
    else:
        # check min and max values if they exist
        if max_value and min_value:
            if plan_field["value"] > max_value:
                result["errors"].append(f"Plan field {field} doesn't respect max value")
            if plan_field["value"] < min_value:
                result["errors"].append(f"Plan field {field} doesn't respect min value")
        #new_plan_object.config_attributes[field] = plan_field["value"]
        config_attributes[field] = plan_field["value"]


def prepare_check_plan_field_value(plan_field, field, result):
    min_value = max_value = value_type = None
    # get value type, min_value and max_value if they're in the plan form
    if plan_field.get("value_type"):
        value_type = plan_field["value_type"]
        # If value type doesn't match with the value from the form, add an error to result
        if type(plan_field["value"]) == str and ast.literal_eval(plan_field["value"]) != value_type:
            result["errors"].append(f"Field {field} value doesn't correspond to the assigned type (type required : {value_type})")
    if plan_field.get("min_value"):
        min_value = plan_field["min_value"]
        if type(min_value) == str:
            min_value = ast.literal_eval(min_value)
    if plan_field.get("max_value"):
        max_value = plan_field["max_value"]
        if type(max_value) == str:
            max_value = ast.literal_eval(max_value)
    return value_type, min_value, max_value


def process_sequence(yaml_content, seq, config, is_simplified, result, user_sp):
    
    # From user sp, get all SP that can observe / submit sequence for the current period
    sp_list = ScientificProgram.objects.observable_programs().filter(id__in=user_sp)
    # Create a Sequence form
    sequence_form = SequenceForm(instance=seq, data_from_config=config.getEditableMountAttributes(config.unit_name), layouts = config.get_layouts(config.unit_name), sp_list=sp_list)

    if is_simplified:
        seq.scientific_program = sp_list[yaml_content["sequence"]["scientific_program"]]    
    else:
        # get scientific program field's attributes 
        yaml_seq_sp = yaml_content["sequence"]["scientific_program"]
        sp_index_value = yaml_seq_sp["value"]
        values =  yaml_seq_sp["values"]
        # Check if index of sp is valid (in range of possible index from values)
        if sp_index_value < 0 or sp_index_value > len(values):
            result["errors"].append(f"SP value isn't valid, index out of bounds ({sp_index_value} > {len(values)})")
            sp_index_value = 0
        chosen_sp = ScientificProgram.objects.get(name=values[sp_index_value])
        # If the sp is associated to that user, associate the sp to the sequence
        if chosen_sp in sp_list:
            #seq.scientific_program = ScientificProgram.objects.get(name=yaml_content["sequence"]["scientific_program"]["values"][sp_index_value])
            seq.scientific_program = chosen_sp
        else:
            result["errors"].append(f"SP {chosen_sp.name} is not assigned to that user ")
    
    seq.config_attributes = {}

    # Fill all Sequence form fields
    #with silk_profile(name="iterate sequence fields form"):
    for field, field_attributes in sequence_form.fields.items():
        #if sequence_form.fields[field].required == False or field == "scientific_program":
        if not field_attributes.required or field=="scientific_program":
            continue
        # pour lisibilité, simplicité et éviter redondance
        yaml_field = yaml_content["sequence"][field]
        value = yaml_field if is_simplified else yaml_field["value"]
545ecb30   Alexis Koralewski   Add ephem to pick...
347
        
793d0190   Alexis Koralewski   rework routine_ma...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
        ''' (orig)
        if is_simplified:
            value = yaml_content["sequence"][field]
        else:
            value = yaml_content["sequence"][field]["value"]
        '''
        # If the current field of the sequence isn't found in the file, add an error message to inform the user the missing field
        if field not in yaml_content["sequence"]:
            result["errors"].append(f"{field} not in yaml file")
        else:
            if is_simplified:
                # If the field is a choicefield, get choices and associate the index to the real value
                if sequence_form.fields[field].__dict__.get("_choices"):
                    # y a pas conflit ici avec la variable "value" définie au-dessus ? -> Non car on transforme l'ancien value qui est un index en une vraie valeur
                    values = [value[0] for value in sequence_form.fields[field].__dict__.get("_choices")]
                    value = values[value]
2dd6bd6c   Alexis Koralewski   try to fix error ...
364
365
366
367
368
369
370
                # Transform the string value to a datetime value
                if field == "start_date":
                    if type(value) != datetime.datetime:
                        #value = datetime.datetime.strptime(yaml_content["sequence"][field]["value"],'%d/%m/%Y %H:%M:%S')
                        # ISO format
                        value = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f')
                        seq.__dict__[field] = value
793d0190   Alexis Koralewski   rework routine_ma...
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
            else:
                if yaml_field.get("values"):
                    # Transform the original value which is an index to a "real" value from the "values" attributes
                    index_value = yaml_field["value"]
                    values = yaml_field["values"]
                    if index_value < 0 or index_value > len(yaml_field["values"]):
                        result["errors"].append(f"Value of {field} isn't valid, index out of bounds ({index_value} > {len(values)})")
                        index_value = 0
                    value = yaml_field["values"][index_value]
                else:
                    # Transform the string value to a datetime value
                    if field == "start_date":
                        if type(value) != datetime.datetime:
                            #value = datetime.datetime.strptime(yaml_content["sequence"][field]["value"],'%d/%m/%Y %H:%M:%S')
                            # ISO format
                            value = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f')
                            seq.__dict__[field] = value
        ''' (orig)
        else:
            if not is_simplified:
                if yaml_content["sequence"][field].get("values"):
                    index_value = yaml_content["sequence"][field]["value"]
                    values =  yaml_content["sequence"][field]["values"]
                    if index_value < 0 or index_value > len(yaml_content["sequence"][field]["values"]):
                        result["errors"].append(f"Value of {field} isn't valid, index out of bounds ({index_value} > {len(values)})")
                        index_value = 0
                    value = yaml_content["sequence"][field]["values"][index_value]
                else:
                    if field == "start_date":
                        if type(value) != datetime.datetime:
                            #value = datetime.datetime.strptime(yaml_content["sequence"][field]["value"],'%d/%m/%Y %H:%M:%S')
                            # ISO format
                            value = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f')
                            seq.__dict__[field] = value
            else:
                if sequence_form.fields[field].__dict__.get("_choices"):
                    values = [value[0] for value in sequence_form.fields[field].__dict__.get("_choices")]
                    value = values[value]
        '''

        # suffisant ? => if field in seq.__dict__
        # If field is an attribute of the sequence, associate the field to the value
        if field in seq.__dict__:
            seq.__dict__[field] = value
        else:
            # else associate field & value in config_attributes sequence's field (JsonField) = variable fields of an sequence
            seq.config_attributes[field] = value

13b26571   Alexis Koralewski   Add night_id to s...
419
420
421
422
423
424
425
426
427
428
429
430

def create_sequence_pickle(sequence):
    seq_dict = model_to_dict(sequence)
    fullseq_dict = {
        "sequence":seq_dict,
        "albums": {}
    }
    for album in sequence.albums.all():
        fullseq_dict["albums"][album.name] = {"plans" : []}
        for plan in album.plans.all():
            fullseq_dict["albums"][f"{album.name}"]["plans"].append(model_to_dict(instance=plan))
    period = sequence.period
545ecb30   Alexis Koralewski   Add ephem to pick...
431
432
433
434
435
436
437
438
439
440
    # Old folder & file creation
    # root_project_path = os.environ.get("PROJECT_ROOT_PATH")
    # data_path = root_project_path + "/data/"
    # if not os.path.exists(data_path + "sequences_pickle"):
    #     os.mkdir(data_path +"sequences_pickle")
    # if not os.path.exists(data_path + f"sequences_pickle/P{period.id}"):
    #     os.mkdir(data_path + f"sequences_pickle/P{period.id}")
    # if not os.path.exists(data_path +f"sequences_pickle/P{period.id}/{sequence.night_id}"):
    #     os.mkdir(data_path +f"sequences_pickle/P{period.id}/{sequence.night_id}")
    # seq_pickle_file_name = data_path +f"./sequences_pickle/P{period.id}/{sequence.night_id}/{sequence.id}.p"
793d0190   Alexis Koralewski   rework routine_ma...
441
    # get guitastro ephemeris
545ecb30   Alexis Koralewski   Add ephem to pick...
442
443
444
    unit_name = os.environ["unit_name"]
    config = OBSConfig(os.environ["PATH_TO_OBSCONF_FILE"], unit_name)
    pyros_config = ConfigPyros(os.environ["pyros_config_file"])
d3e71677   Alexis Koralewski   Put seq & eph fn_...
445
    config.fn.fcontext = "pyros_seq"
8a9bdc27   Alexis Koralewski   add transaction a...
446
447
    # home = guitastro.Home(config.getHome())
    # config.fn.longitude = home.longitude
5c709a6e   Alexis Koralewski   Add ephemeris cal...
448
    period_id = str(period.id)
545ecb30   Alexis Koralewski   Add ephem to pick...
449
    if len(str(period.id)) < 3:
545ecb30   Alexis Koralewski   Add ephem to pick...
450
451
452
453
454
455
456
457
458
        while len(period_id) < 3:
            period_id = "0" + period_id
    fn_param = {
        "period" : f"P{period_id}",
        "version": "1",
        "unit": config.unit_name,
        "date": sequence.night_id,
        "id_seq": sequence.id
    }
d3e71677   Alexis Koralewski   Put seq & eph fn_...
459
460
    config.fn.fname = config.fn.naming_set(fn_param)
    fpath_name = config.fn.join(config.fn.fname)
545ecb30   Alexis Koralewski   Add ephem to pick...
461
462
    # create dirs if they don't exist
    os.makedirs(os.path.dirname(fpath_name), exist_ok=True)
b95a693f   Alexis Koralewski   restructuration d...
463
    print(fpath_name)
545ecb30   Alexis Koralewski   Add ephem to pick...
464
465
466
467
    eph = guitastro.Ephemeris()
    eph.set_home(config.getHome())
    # duskelev a parametrer dans obsconfig (yml)
    duskelev = -7
5c709a6e   Alexis Koralewski   Add ephemeris cal...
468
    errors = []
545ecb30   Alexis Koralewski   Add ephem to pick...
469
470
    try:
        # TODO remplacer les none par les fichiers pickle de ephem_sun & ephem_moon
3ee14364   Alexis Koralewski   Sequence two pic...
471
        #fullseq_dict["ephem"] = eph.target2night(fullseq_dict["sequence"]["config_attributes"]["target"], sequence.night_id, None, None, preferance=sequence.start_expo_pref, duskelev=duskelev)
b94d1143   Alexis Koralewski   typo preference t...
472
        ephem = eph.target2night(fullseq_dict["sequence"]["config_attributes"]["target"], sequence.night_id, None, None, preference=sequence.start_expo_pref, duskelev=duskelev)
5c709a6e   Alexis Koralewski   Add ephemeris cal...
473
474
475
476
477
478
479
480
481
482
    except ValueError:
        errors.append("Target value is not valid")
    except guitastro.ephemeris.EphemerisException as ephemException:
        errors.append(str(ephemException))
    if len(errors) == 0 and numpy.sum(ephem["visibility"]) == 0 :
        errors.append("Target is not visible.")
    if len(errors) == 0:
        pickle.dump(ephem, open(f"{fpath_name[:-2]}.f","wb"))
        pickle.dump(fullseq_dict, open(fpath_name,"wb"))
    return errors