Commit 591253988601fcc7b3dcaff9bc6c70803f6beec3
1 parent
d5474086
Exists in
master
Improve resilience.
Showing
1 changed file
with
275 additions
and
268 deletions
Show diff stats
flaskr/controllers/main_controller.py
@@ -240,318 +240,325 @@ def compute(): # process the queue of estimation requests | @@ -240,318 +240,325 @@ def compute(): # process the queue of estimation requests | ||
240 | _estimation.warnings = _warning_message | 240 | _estimation.warnings = _warning_message |
241 | db.session.commit() | 241 | db.session.commit() |
242 | 242 | ||
243 | - response = "" | 243 | + try: |
244 | + response = "" | ||
244 | 245 | ||
245 | - count_working = Estimation.query \ | ||
246 | - .filter_by(status=StatusEnum.working) \ | ||
247 | - .count() | 246 | + count_working = Estimation.query \ |
247 | + .filter_by(status=StatusEnum.working) \ | ||
248 | + .count() | ||
248 | 249 | ||
249 | - if 0 < count_working: | ||
250 | - return _respond("Already working on estimation.") | 250 | + if 0 < count_working: |
251 | + return _respond("Already working on estimation.") | ||
251 | 252 | ||
252 | - try: | ||
253 | - estimation = Estimation.query \ | ||
254 | - .filter_by(status=StatusEnum.pending) \ | ||
255 | - .order_by(Estimation.id.asc()) \ | ||
256 | - .first() | ||
257 | - except sqlalchemy.orm.exc.NoResultFound: | ||
258 | - return _respond("No estimation in the queue.") | ||
259 | - except Exception as e: | ||
260 | - return _respond("Database error: %s" % (e,)) | 253 | + try: |
254 | + estimation = Estimation.query \ | ||
255 | + .filter_by(status=StatusEnum.pending) \ | ||
256 | + .order_by(Estimation.id.asc()) \ | ||
257 | + .first() | ||
258 | + except sqlalchemy.orm.exc.NoResultFound: | ||
259 | + return _respond("No estimation in the queue.") | ||
260 | + except Exception as e: | ||
261 | + return _respond("Database error: %s" % (e,)) | ||
262 | + | ||
263 | + if not estimation: | ||
264 | + return _respond("No estimation in the queue.") | ||
265 | + | ||
266 | + estimation.status = StatusEnum.working | ||
267 | + db.session.commit() | ||
261 | 268 | ||
262 | - if not estimation: | ||
263 | - return _respond("No estimation in the queue.") | 269 | + response += u"Processing estimation `%s`...\n" % ( |
270 | + estimation.public_id | ||
271 | + ) | ||
264 | 272 | ||
265 | - estimation.status = StatusEnum.working | ||
266 | - db.session.commit() | 273 | + failed_addresses = [] |
274 | + geocoder = CachedGeocoder() | ||
267 | 275 | ||
268 | - response += u"Processing estimation `%s`...\n" % ( | ||
269 | - estimation.public_id | ||
270 | - ) | 276 | + # GEOCODE ORIGINS ######################################################### |
271 | 277 | ||
272 | - failed_addresses = [] | ||
273 | - geocoder = CachedGeocoder() | 278 | + origins_addresses = estimation.origin_addresses.strip().split("\n") |
279 | + origins = [] | ||
274 | 280 | ||
275 | - # GEOCODE ORIGINS ######################################################### | 281 | + for i in range(len(origins_addresses)): |
276 | 282 | ||
277 | - origins_addresses = estimation.origin_addresses.strip().split("\n") | ||
278 | - origins = [] | 283 | + origin_address = origins_addresses[i].strip() |
284 | + if origin_address in failed_addresses: | ||
285 | + continue | ||
279 | 286 | ||
280 | - for i in range(len(origins_addresses)): | 287 | + try: |
288 | + origin = geocoder.geocode(origin_address.encode('utf-8')) | ||
289 | + except geopy.exc.GeopyError as e: | ||
290 | + response += u"Failed to geocode origin `%s`.\n%s\n" % ( | ||
291 | + origin_address, e, | ||
292 | + ) | ||
293 | + _handle_warning(estimation, response) | ||
294 | + failed_addresses.append(origin_address) | ||
295 | + continue | ||
281 | 296 | ||
282 | - origin_address = origins_addresses[i].strip() | ||
283 | - if origin_address in failed_addresses: | ||
284 | - continue | 297 | + if origin is None: |
298 | + response += u"Failed to geocode origin `%s`.\n" % ( | ||
299 | + origin_address, | ||
300 | + ) | ||
301 | + _handle_warning(estimation, response) | ||
302 | + failed_addresses.append(origin_address) | ||
303 | + continue | ||
285 | 304 | ||
286 | - try: | ||
287 | - origin = geocoder.geocode(origin_address.encode('utf-8')) | ||
288 | - except geopy.exc.GeopyError as e: | ||
289 | - response += u"Failed to geocode origin `%s`.\n%s\n" % ( | ||
290 | - origin_address, e, | ||
291 | - ) | ||
292 | - _handle_warning(estimation, response) | ||
293 | - failed_addresses.append(origin_address) | ||
294 | - continue | 305 | + origins.append(origin) |
295 | 306 | ||
296 | - if origin is None: | ||
297 | - response += u"Failed to geocode origin `%s`.\n" % ( | ||
298 | - origin_address, | 307 | + response += u"Origin: %s == %s (%f, %f)\n" % ( |
308 | + origin_address, origin.address, | ||
309 | + origin.latitude, origin.longitude, | ||
299 | ) | 310 | ) |
300 | - _handle_warning(estimation, response) | ||
301 | - failed_addresses.append(origin_address) | ||
302 | - continue | ||
303 | 311 | ||
304 | - origins.append(origin) | 312 | + # GEOCODE DESTINATIONS #################################################### |
305 | 313 | ||
306 | - response += u"Origin: %s == %s (%f, %f)\n" % ( | ||
307 | - origin_address, origin.address, | ||
308 | - origin.latitude, origin.longitude, | ||
309 | - ) | 314 | + destinations_addresses = estimation.destination_addresses.strip().split("\n") |
315 | + destinations = [] | ||
310 | 316 | ||
311 | - # GEOCODE DESTINATIONS #################################################### | 317 | + for i in range(len(destinations_addresses)): |
312 | 318 | ||
313 | - destinations_addresses = estimation.destination_addresses.strip().split("\n") | ||
314 | - destinations = [] | 319 | + destination_address = destinations_addresses[i].strip() |
320 | + if destination_address in failed_addresses: | ||
321 | + continue | ||
315 | 322 | ||
316 | - for i in range(len(destinations_addresses)): | 323 | + try: |
324 | + destination = geocoder.geocode(destination_address.encode('utf-8')) | ||
325 | + except geopy.exc.GeopyError as e: | ||
326 | + response += u"Failed to geocode destination `%s`.\n%s\n" % ( | ||
327 | + destination_address, e, | ||
328 | + ) | ||
329 | + _handle_warning(estimation, response) | ||
330 | + failed_addresses.append(destination_address) | ||
331 | + continue | ||
317 | 332 | ||
318 | - destination_address = destinations_addresses[i].strip() | ||
319 | - if destination_address in failed_addresses: | ||
320 | - continue | 333 | + if destination is None: |
334 | + response += u"Failed to geocode destination `%s`.\n" % ( | ||
335 | + destination_address, | ||
336 | + ) | ||
337 | + _handle_warning(estimation, response) | ||
338 | + failed_addresses.append(destination_address) | ||
339 | + continue | ||
321 | 340 | ||
322 | - try: | ||
323 | - destination = geocoder.geocode(destination_address.encode('utf-8')) | ||
324 | - except geopy.exc.GeopyError as e: | ||
325 | - response += u"Failed to geocode destination `%s`.\n%s\n" % ( | ||
326 | - destination_address, e, | ||
327 | - ) | ||
328 | - _handle_warning(estimation, response) | ||
329 | - failed_addresses.append(destination_address) | ||
330 | - continue | 341 | + # print(repr(destination.raw)) |
331 | 342 | ||
332 | - if destination is None: | ||
333 | - response += u"Failed to geocode destination `%s`.\n" % ( | ||
334 | - destination_address, | 343 | + destinations.append(destination) |
344 | + | ||
345 | + response += u"Destination: %s == %s (%f, %f)\n" % ( | ||
346 | + destination_address, destination.address, | ||
347 | + destination.latitude, destination.longitude, | ||
335 | ) | 348 | ) |
336 | - _handle_warning(estimation, response) | ||
337 | - failed_addresses.append(destination_address) | ||
338 | - continue | ||
339 | 349 | ||
340 | - # print(repr(destination.raw)) | 350 | + # GTFO IF NO ORIGINS OR NO DESTINATIONS ################################### |
341 | 351 | ||
342 | - destinations.append(destination) | 352 | + if 0 == len(origins): |
353 | + response += u"Failed to geocode all the origin(s).\n" | ||
354 | + _handle_failure(estimation, response) | ||
355 | + return _respond(response) | ||
356 | + if 0 == len(destinations): | ||
357 | + response += u"Failed to geocode all the destination(s).\n" | ||
358 | + _handle_failure(estimation, response) | ||
359 | + return _respond(response) | ||
343 | 360 | ||
344 | - response += u"Destination: %s == %s (%f, %f)\n" % ( | ||
345 | - destination_address, destination.address, | ||
346 | - destination.latitude, destination.longitude, | ||
347 | - ) | 361 | + # GRAB AND CONFIGURE THE EMISSION MODELS ################################## |
348 | 362 | ||
349 | - # GTFO IF NO ORIGINS OR NO DESTINATIONS ################################### | 363 | + emission_models = estimation.get_models() |
364 | + # print(emission_models) | ||
350 | 365 | ||
351 | - if 0 == len(origins): | ||
352 | - response += u"Failed to geocode all the origin(s).\n" | ||
353 | - _handle_failure(estimation, response) | ||
354 | - return _respond(response) | ||
355 | - if 0 == len(destinations): | ||
356 | - response += u"Failed to geocode all the destination(s).\n" | ||
357 | - _handle_failure(estimation, response) | ||
358 | - return _respond(response) | ||
359 | - | ||
360 | - # GRAB AND CONFIGURE THE EMISSION MODELS ################################## | ||
361 | - | ||
362 | - emission_models = estimation.get_models() | ||
363 | - # print(emission_models) | ||
364 | - | ||
365 | - extra_config = { | ||
366 | - 'use_train_below_distance': estimation.use_train_below_km, | ||
367 | - # 'use_train_below_distance': 300, | ||
368 | - } | ||
369 | - | ||
370 | - # PREPARE RESULT DICTIONARY THAT WILL BE STORED ########################### | ||
371 | - | ||
372 | - results = {} | ||
373 | - | ||
374 | - # UTILITY PRIVATE FUNCTION(S) ############################################# | ||
375 | - | ||
376 | - def get_city_key(_location): | ||
377 | - # Will this hack hold? Suspense... | ||
378 | - return _location.address.split(',')[0] | ||
379 | - | ||
380 | - # _city_key = _location.address | ||
381 | - # # if 'address100' in _location.raw['address']: | ||
382 | - # # _city_key = _location.raw['address']['address100'] | ||
383 | - # if 'city' in _location.raw['address']: | ||
384 | - # _city_key = _location.raw['address']['city'] | ||
385 | - # elif 'state' in _location.raw['address']: | ||
386 | - # _city_key = _location.raw['address']['state'] | ||
387 | - # return _city_key | ||
388 | - | ||
389 | - def compute_one_to_many( | ||
390 | - _origin, | ||
391 | - _destinations, | ||
392 | - _extra_config=None | ||
393 | - ): | ||
394 | - _results = {} | ||
395 | - footprints = {} | ||
396 | - | ||
397 | - destinations_by_city_key = {} | ||
398 | - | ||
399 | - cities_sum_foot = {} | ||
400 | - cities_sum_dist = {} | ||
401 | - cities_dict_first_model = None | ||
402 | - for model in emission_models: | ||
403 | - cities_dict = {} | ||
404 | - for _destination in _destinations: | ||
405 | - footprint = model.compute_travel_footprint( | ||
406 | - origin_latitude=_origin.latitude, | ||
407 | - origin_longitude=_origin.longitude, | ||
408 | - destination_latitude=_destination.latitude, | ||
409 | - destination_longitude=_destination.longitude, | ||
410 | - extra_config=_extra_config, | ||
411 | - ) | 366 | + extra_config = { |
367 | + 'use_train_below_distance': estimation.use_train_below_km, | ||
368 | + # 'use_train_below_distance': 300, | ||
369 | + } | ||
412 | 370 | ||
413 | - _key = get_city_key(_destination) | ||
414 | - | ||
415 | - destinations_by_city_key[_key] = _destination | ||
416 | - | ||
417 | - if _key not in cities_dict: | ||
418 | - cities_dict[_key] = { | ||
419 | - 'city': _key, | ||
420 | - 'address': _destination.address, | ||
421 | - 'footprint': 0.0, | ||
422 | - 'distance': 0.0, | ||
423 | - 'train_trips': 0, | ||
424 | - 'plane_trips': 0, | ||
425 | - } | ||
426 | - cities_dict[_key]['footprint'] += footprint['co2eq_kg'] | ||
427 | - cities_dict[_key]['distance'] += footprint['distance_km'] | ||
428 | - cities_dict[_key]['train_trips'] += footprint['train_trips'] | ||
429 | - cities_dict[_key]['plane_trips'] += footprint['plane_trips'] | ||
430 | - if _key not in cities_sum_foot: | ||
431 | - cities_sum_foot[_key] = 0.0 | ||
432 | - cities_sum_foot[_key] += footprint['co2eq_kg'] | ||
433 | - if _key not in cities_sum_dist: | ||
434 | - cities_sum_dist[_key] = 0.0 | ||
435 | - cities_sum_dist[_key] += footprint['distance_km'] | ||
436 | - | ||
437 | - cities = sorted(cities_dict.values(), key=lambda c: c['footprint']) | ||
438 | - | ||
439 | - footprints[model.slug] = { | ||
440 | - 'cities': cities, | ||
441 | - } | 371 | + # PREPARE RESULT DICTIONARY THAT WILL BE STORED ########################### |
372 | + | ||
373 | + results = {} | ||
374 | + | ||
375 | + # UTILITY PRIVATE FUNCTION(S) ############################################# | ||
376 | + | ||
377 | + def get_city_key(_location): | ||
378 | + # Will this hack hold? Suspense... | ||
379 | + return _location.address.split(',')[0] | ||
380 | + | ||
381 | + # _city_key = _location.address | ||
382 | + # # if 'address100' in _location.raw['address']: | ||
383 | + # # _city_key = _location.raw['address']['address100'] | ||
384 | + # if 'city' in _location.raw['address']: | ||
385 | + # _city_key = _location.raw['address']['city'] | ||
386 | + # elif 'state' in _location.raw['address']: | ||
387 | + # _city_key = _location.raw['address']['state'] | ||
388 | + # return _city_key | ||
389 | + | ||
390 | + def compute_one_to_many( | ||
391 | + _origin, | ||
392 | + _destinations, | ||
393 | + _extra_config=None | ||
394 | + ): | ||
395 | + _results = {} | ||
396 | + footprints = {} | ||
397 | + | ||
398 | + destinations_by_city_key = {} | ||
399 | + | ||
400 | + cities_sum_foot = {} | ||
401 | + cities_sum_dist = {} | ||
402 | + cities_dict_first_model = None | ||
403 | + for model in emission_models: | ||
404 | + cities_dict = {} | ||
405 | + for _destination in _destinations: | ||
406 | + footprint = model.compute_travel_footprint( | ||
407 | + origin_latitude=_origin.latitude, | ||
408 | + origin_longitude=_origin.longitude, | ||
409 | + destination_latitude=_destination.latitude, | ||
410 | + destination_longitude=_destination.longitude, | ||
411 | + extra_config=_extra_config, | ||
412 | + ) | ||
442 | 413 | ||
443 | - if cities_dict_first_model is None: | ||
444 | - cities_dict_first_model = deepcopy(cities_dict) | ||
445 | - | ||
446 | - _results['footprints'] = footprints | ||
447 | - | ||
448 | - total_foot = 0.0 | ||
449 | - total_dist = 0.0 | ||
450 | - total_train_trips = 0 | ||
451 | - total_plane_trips = 0 | ||
452 | - | ||
453 | - cities_mean_dict = {} | ||
454 | - for city in cities_sum_foot.keys(): | ||
455 | - city_mean_foot = 1.0 * cities_sum_foot[city] / len(emission_models) | ||
456 | - city_mean_dist = 1.0 * cities_sum_dist[city] / len(emission_models) | ||
457 | - city_train_trips = cities_dict_first_model[city]['train_trips'] | ||
458 | - city_plane_trips = cities_dict_first_model[city]['plane_trips'] | ||
459 | - cities_mean_dict[city] = { | ||
460 | - 'address': destinations_by_city_key[city].address, | ||
461 | - 'city': city, | ||
462 | - 'footprint': city_mean_foot, | ||
463 | - 'distance': city_mean_dist, | ||
464 | - 'train_trips': city_train_trips, | ||
465 | - 'plane_trips': city_plane_trips, | 414 | + _key = get_city_key(_destination) |
415 | + | ||
416 | + destinations_by_city_key[_key] = _destination | ||
417 | + | ||
418 | + if _key not in cities_dict: | ||
419 | + cities_dict[_key] = { | ||
420 | + 'city': _key, | ||
421 | + 'address': _destination.address, | ||
422 | + 'footprint': 0.0, | ||
423 | + 'distance': 0.0, | ||
424 | + 'train_trips': 0, | ||
425 | + 'plane_trips': 0, | ||
426 | + } | ||
427 | + cities_dict[_key]['footprint'] += footprint['co2eq_kg'] | ||
428 | + cities_dict[_key]['distance'] += footprint['distance_km'] | ||
429 | + cities_dict[_key]['train_trips'] += footprint['train_trips'] | ||
430 | + cities_dict[_key]['plane_trips'] += footprint['plane_trips'] | ||
431 | + if _key not in cities_sum_foot: | ||
432 | + cities_sum_foot[_key] = 0.0 | ||
433 | + cities_sum_foot[_key] += footprint['co2eq_kg'] | ||
434 | + if _key not in cities_sum_dist: | ||
435 | + cities_sum_dist[_key] = 0.0 | ||
436 | + cities_sum_dist[_key] += footprint['distance_km'] | ||
437 | + | ||
438 | + cities = sorted(cities_dict.values(), key=lambda c: c['footprint']) | ||
439 | + | ||
440 | + footprints[model.slug] = { | ||
441 | + 'cities': cities, | ||
442 | + } | ||
443 | + | ||
444 | + if cities_dict_first_model is None: | ||
445 | + cities_dict_first_model = deepcopy(cities_dict) | ||
446 | + | ||
447 | + _results['footprints'] = footprints | ||
448 | + | ||
449 | + total_foot = 0.0 | ||
450 | + total_dist = 0.0 | ||
451 | + total_train_trips = 0 | ||
452 | + total_plane_trips = 0 | ||
453 | + | ||
454 | + cities_mean_dict = {} | ||
455 | + for city in cities_sum_foot.keys(): | ||
456 | + city_mean_foot = 1.0 * cities_sum_foot[city] / len(emission_models) | ||
457 | + city_mean_dist = 1.0 * cities_sum_dist[city] / len(emission_models) | ||
458 | + city_train_trips = cities_dict_first_model[city]['train_trips'] | ||
459 | + city_plane_trips = cities_dict_first_model[city]['plane_trips'] | ||
460 | + cities_mean_dict[city] = { | ||
461 | + 'address': destinations_by_city_key[city].address, | ||
462 | + 'city': city, | ||
463 | + 'footprint': city_mean_foot, | ||
464 | + 'distance': city_mean_dist, | ||
465 | + 'train_trips': city_train_trips, | ||
466 | + 'plane_trips': city_plane_trips, | ||
467 | + } | ||
468 | + total_foot += city_mean_foot | ||
469 | + total_dist += city_mean_dist | ||
470 | + total_train_trips += city_train_trips | ||
471 | + total_plane_trips += city_plane_trips | ||
472 | + | ||
473 | + cities_mean = [cities_mean_dict[k] for k in cities_mean_dict.keys()] | ||
474 | + cities_mean = sorted(cities_mean, key=lambda c: c['footprint']) | ||
475 | + | ||
476 | + _results['mean_footprint'] = { # DEPRECATED? | ||
477 | + 'cities': cities_mean | ||
466 | } | 478 | } |
467 | - total_foot += city_mean_foot | ||
468 | - total_dist += city_mean_dist | ||
469 | - total_train_trips += city_train_trips | ||
470 | - total_plane_trips += city_plane_trips | 479 | + _results['cities'] = cities_mean |
471 | 480 | ||
472 | - cities_mean = [cities_mean_dict[k] for k in cities_mean_dict.keys()] | ||
473 | - cities_mean = sorted(cities_mean, key=lambda c: c['footprint']) | 481 | + _results['total'] = total_foot # DEPRECATED |
482 | + _results['footprint'] = total_foot | ||
474 | 483 | ||
475 | - _results['mean_footprint'] = { # DEPRECATED? | ||
476 | - 'cities': cities_mean | ||
477 | - } | ||
478 | - _results['cities'] = cities_mean | ||
479 | - | ||
480 | - _results['total'] = total_foot # DEPRECATED | ||
481 | - _results['footprint'] = total_foot | ||
482 | - | ||
483 | - _results['distance'] = total_dist | ||
484 | - _results['train_trips'] = total_train_trips | ||
485 | - _results['plane_trips'] = total_plane_trips | ||
486 | - | ||
487 | - return _results | ||
488 | - | ||
489 | - # SCENARIO A : One Origin, At Least One Destination ####################### | ||
490 | - # | ||
491 | - # In this scenario, we compute the sum of each of the travels' footprint, | ||
492 | - # for each of the Emission Models, and present a mean of all Models. | ||
493 | - # | ||
494 | - if 1 == len(origins): | ||
495 | - estimation.scenario = ScenarioEnum.one_to_many | ||
496 | - results = compute_one_to_many( | ||
497 | - _origin=origins[0], | ||
498 | - _destinations=destinations, | ||
499 | - _extra_config=extra_config, | ||
500 | - ) | 484 | + _results['distance'] = total_dist |
485 | + _results['train_trips'] = total_train_trips | ||
486 | + _results['plane_trips'] = total_plane_trips | ||
501 | 487 | ||
502 | - # SCENARIO B : At Least One Origin, One Destination ####################### | ||
503 | - # | ||
504 | - # Same as A for now. | ||
505 | - # | ||
506 | - elif 1 == len(destinations): | ||
507 | - estimation.scenario = ScenarioEnum.many_to_one | ||
508 | - results = compute_one_to_many( | ||
509 | - _origin=destinations[0], | ||
510 | - _destinations=origins, | ||
511 | - _extra_config=extra_config, | ||
512 | - ) | 488 | + return _results |
513 | 489 | ||
514 | - # SCENARIO C : At Least One Origin, At Least One Destination ############## | ||
515 | - # | ||
516 | - # Run Scenario A for each Destination, and expose optimum Destination. | ||
517 | - # | ||
518 | - else: | ||
519 | - estimation.scenario = ScenarioEnum.many_to_many | ||
520 | - unique_city_keys = [] | ||
521 | - result_cities = [] | ||
522 | - for destination in destinations: | ||
523 | - city_key = get_city_key(destination) | ||
524 | - | ||
525 | - if city_key in unique_city_keys: | ||
526 | - continue | ||
527 | - else: | ||
528 | - unique_city_keys.append(city_key) | 490 | + # SCENARIO A : One Origin, At Least One Destination ####################### |
491 | + # | ||
492 | + # In this scenario, we compute the sum of each of the travels' footprint, | ||
493 | + # for each of the Emission Models, and present a mean of all Models. | ||
494 | + # | ||
495 | + if 1 == len(origins): | ||
496 | + estimation.scenario = ScenarioEnum.one_to_many | ||
497 | + results = compute_one_to_many( | ||
498 | + _origin=origins[0], | ||
499 | + _destinations=destinations, | ||
500 | + _extra_config=extra_config, | ||
501 | + ) | ||
529 | 502 | ||
530 | - city_results = compute_one_to_many( | ||
531 | - _origin=destination, | 503 | + # SCENARIO B : At Least One Origin, One Destination ####################### |
504 | + # | ||
505 | + # Same as A for now. | ||
506 | + # | ||
507 | + elif 1 == len(destinations): | ||
508 | + estimation.scenario = ScenarioEnum.many_to_one | ||
509 | + results = compute_one_to_many( | ||
510 | + _origin=destinations[0], | ||
532 | _destinations=origins, | 511 | _destinations=origins, |
533 | _extra_config=extra_config, | 512 | _extra_config=extra_config, |
534 | ) | 513 | ) |
535 | - city_results['city'] = city_key | ||
536 | - city_results['address'] = destination.address | ||
537 | - result_cities.append(city_results) | ||
538 | 514 | ||
539 | - result_cities = sorted(result_cities, key=lambda c: int(c['footprint'])) | ||
540 | - results = { | ||
541 | - 'cities': result_cities, | ||
542 | - } | 515 | + # SCENARIO C : At Least One Origin, At Least One Destination ############## |
516 | + # | ||
517 | + # Run Scenario A for each Destination, and expose optimum Destination. | ||
518 | + # | ||
519 | + else: | ||
520 | + estimation.scenario = ScenarioEnum.many_to_many | ||
521 | + unique_city_keys = [] | ||
522 | + result_cities = [] | ||
523 | + for destination in destinations: | ||
524 | + city_key = get_city_key(destination) | ||
525 | + | ||
526 | + if city_key in unique_city_keys: | ||
527 | + continue | ||
528 | + else: | ||
529 | + unique_city_keys.append(city_key) | ||
543 | 530 | ||
544 | - # WRITE RESULTS INTO THE DATABASE ######################################### | 531 | + city_results = compute_one_to_many( |
532 | + _origin=destination, | ||
533 | + _destinations=origins, | ||
534 | + _extra_config=extra_config, | ||
535 | + ) | ||
536 | + city_results['city'] = city_key | ||
537 | + city_results['address'] = destination.address | ||
538 | + result_cities.append(city_results) | ||
539 | + | ||
540 | + result_cities = sorted(result_cities, key=lambda c: int(c['footprint'])) | ||
541 | + results = { | ||
542 | + 'cities': result_cities, | ||
543 | + } | ||
544 | + | ||
545 | + # WRITE RESULTS INTO THE DATABASE ######################################### | ||
545 | 546 | ||
546 | - estimation.status = StatusEnum.success | ||
547 | - estimation.output_yaml = yaml_dump(results) | ||
548 | - db.session.commit() | 547 | + estimation.status = StatusEnum.success |
548 | + estimation.output_yaml = yaml_dump(results) | ||
549 | + db.session.commit() | ||
550 | + | ||
551 | + # FINALLY, RESPOND ######################################################## | ||
549 | 552 | ||
550 | - # FINALLY, RESPOND ######################################################## | 553 | + response += yaml_dump(results) + "\n" |
551 | 554 | ||
552 | - response += yaml_dump(results) + "\n" | 555 | + return _respond(response) |
553 | 556 | ||
554 | - return _respond(response) | 557 | + except Exception as e: |
558 | + errmsg = "Computation failed : %s" % e | ||
559 | + if estimation: | ||
560 | + _handle_failure(estimation, errmsg) | ||
561 | + return _respond(errmsg) | ||
555 | 562 | ||
556 | 563 | ||
557 | @main.route("/estimation/<public_id>.<extension>") | 564 | @main.route("/estimation/<public_id>.<extension>") |
@@ -563,7 +570,7 @@ def consult_estimation(public_id, extension): | @@ -563,7 +570,7 @@ def consult_estimation(public_id, extension): | ||
563 | except sqlalchemy.orm.exc.NoResultFound: | 570 | except sqlalchemy.orm.exc.NoResultFound: |
564 | return abort(404) | 571 | return abort(404) |
565 | except Exception as e: | 572 | except Exception as e: |
566 | - # TODO: log | 573 | + # TODO: log? |
567 | return abort(500) | 574 | return abort(500) |
568 | 575 | ||
569 | # allowed_formats = ['html'] | 576 | # allowed_formats = ['html'] |