11from typing import List , Optional , Union , Tuple , Dict , Any
22from itertools import groupby
3- from datetime import date , datetime , timedelta
3+ from datetime import date , timedelta
44from epiweeks import Week
55from flask import Blueprint , request
66from flask .json import loads , jsonify
@@ -366,43 +366,39 @@ def gen():
366366def handle_export ():
367367 source , signal = request .args .get ("signal" , "jhu-csse:confirmed_incidence_num" ).split (":" )
368368 source_signal_pairs = [SourceSignalPair (source , [signal ])]
369- _ , weekly_signals = count_signal_time_types (source_signal_pairs )
370- if weekly_signals > 0 :
371- raise ValidationFailedException ('weekly signals are not supported' )
369+ daily_signals , weekly_signals = count_signal_time_types (source_signal_pairs )
372370 source_signal_pairs , alias_mapper = create_source_signal_alias_mapper (source_signal_pairs )
373- start_day = request .args .get ("start_day" , "2020-04-01" )
374- end_day = request .args .get ("end_day" , "2020-09-01" )
371+ start_day , is_day = parse_day_or_week_arg ("start_day" , 202001 if weekly_signals > 0 else 20200401 )
372+ end_day , is_end_day = parse_day_or_week_arg ("end_day" , 202020 if weekly_signals > 0 else 20200901 )
373+ if is_day != is_end_day :
374+ raise ValidationFailedException ("mixing weeks with day arguments" )
375+ _verify_argument_time_type_matches (is_day , daily_signals , weekly_signals )
376+
375377 geo_type = request .args .get ("geo_type" , "county" )
376378 geo_values = request .args .get ("geo_values" , "*" )
377379
378380 if geo_values != "*" :
379381 geo_values = geo_values .split ("," )
380382
381- as_of = request .args .get ("as_of" , None )
382-
383- start_day = datetime .strptime (start_day , "%Y-%m-%d" ).date ()
384- end_day = datetime .strptime (end_day , "%Y-%m-%d" ).date ()
385-
386- if as_of is not None :
387- as_of = datetime .strptime (as_of , "%Y-%m-%d" ).date ()
383+ as_of , is_as_of_day = parse_day_or_week_arg ('as_of' ) if 'as_of' in request .args else None , is_day
384+ if is_day != is_as_of_day :
385+ raise ValidationFailedException ("mixing weeks with day arguments" )
388386
389387 # build query
390388 q = QueryBuilder ("covidcast" , "t" )
391389
392390 q .set_fields (["geo_value" , "signal" , "time_value" , "issue" , "lag" , "value" , "stderr" , "sample_size" , "geo_type" , "source" ], [], [])
393391 q .set_order ("time_value" , "geo_value" )
394- q .where (time_type = "day" )
395392 q .where_source_signal_pairs ("source" , "signal" , source_signal_pairs )
396- q .conditions .append ("time_value BETWEEN :start_day AND :end_day" )
397- q .params ["start_day" ] = date_to_time_value (start_day )
398- q .params ["end_day" ] = date_to_time_value (end_day )
393+ q .where_time_pairs ("time_type" , "time_value" , [TimePair ('day' if is_day else 'week' , [(start_day , end_day )])])
399394 q .where_geo_pairs ("geo_type" , "geo_value" , [GeoPair (geo_type , True if geo_values == "*" else geo_values )])
400395
401- _handle_lag_issues_as_of (q , None , None , date_to_time_value ( as_of ) if as_of is not None else None )
396+ _handle_lag_issues_as_of (q , None , None , as_of )
402397
398+ format_date = time_value_to_iso if is_day else lambda x : week_value_to_week (x ).cdcformat ()
403399 # tag as_of in filename, if it was specified
404- as_of_str = "-asof-{as_of}" .format (as_of = as_of . isoformat ( )) if as_of is not None else ""
405- filename = "covidcast-{source}-{signal}-{start_day}-to-{end_day}{as_of}" .format (source = source , signal = signal , start_day = start_day . isoformat ( ), end_day = end_day . isoformat ( ), as_of = as_of_str )
400+ as_of_str = "-asof-{as_of}" .format (as_of = format_date ( as_of )) if as_of is not None else ""
401+ filename = "covidcast-{source}-{signal}-{start_day}-to-{end_day}{as_of}" .format (source = source , signal = signal , start_day = format_date ( start_day ), end_day = format_date ( end_day ), as_of = as_of_str )
406402 p = CSVPrinter (filename )
407403
408404 def parse_row (i , row ):
@@ -411,8 +407,8 @@ def parse_row(i, row):
411407 "" : i ,
412408 "geo_value" : row ["geo_value" ],
413409 "signal" : row ["signal" ],
414- "time_value" : time_value_to_iso (row ["time_value" ]),
415- "issue" : time_value_to_iso (row ["issue" ]),
410+ "time_value" : time_value_to_iso (row ["time_value" ]) if is_day else row [ "time_value" ] ,
411+ "issue" : time_value_to_iso (row ["issue" ]) if is_day else row [ "issue" ] ,
416412 "lag" : row ["lag" ],
417413 "value" : row ["value" ],
418414 "stderr" : row ["stderr" ],
@@ -436,7 +432,7 @@ def gen(first_row, rows):
436432 first_row = next (r , None )
437433 if not first_row :
438434 return "No matching data found for signal {source}:{signal} " "at {geo} level from {start_day} to {end_day}, as of {as_of}." .format (
439- source = source , signal = signal , geo = geo_type , start_day = start_day . isoformat ( ), end_day = end_day . isoformat ( ), as_of = (date .today ().isoformat () if as_of is None else as_of . isoformat ( ))
435+ source = source , signal = signal , geo = geo_type , start_day = format_date ( start_day ), end_day = format_date ( end_day ), as_of = (date .today ().isoformat () if as_of is None else format_date ( as_of ))
440436 )
441437
442438 # now use a generator for sending the rows and execute all the other queries
0 commit comments