def decorated_service(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'prior' from request." ) return invalid_method(request.method) if "prior" in form: prior = parse_isodate_str(form["prior"]) if ex_post is True: start = parse_isodate_str(form["start"]) duration = parse_duration(form["duration"], start) # todo: validate start and duration (refactor already duplicate code from period_required and optional_horizon_accepted) knowledge_time = ( start + duration ) # todo: take into account knowledge horizon function if prior < knowledge_time: extra_info = "Meter data can only be observed after the fact." return invalid_horizon(extra_info) else: prior = None kwargs["prior"] = prior return fn(*args, **kwargs)
def decorated_service(*args, **kwargs): kwargs[ "resolution" ] = None # using this decorator means you can expect this attribute, None means default form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'resolution' from request." ) return invalid_method(request.method) if "resolution" in form and form["resolution"]: ds_resolution = parse_duration(form["resolution"]) if ds_resolution is None: return invalid_resolution_str(form["resolution"]) # Check if the resolution can be applied to all assets (if it is a multiple # of the event_resolution(s) and thus downsampling is possible) for asset_group in kwargs["generic_asset_name_groups"]: for asset_descriptor in asset_group: generic_asset = get_generic_asset(asset_descriptor, entity_type) if generic_asset is None: return unrecognized_asset() asset_resolution = generic_asset.event_resolution if ds_resolution % asset_resolution != timedelta(minutes=0): return unapplicable_resolution( f"{isodate.duration_isoformat(asset_resolution)} or a multiple hereof." ) kwargs["resolution"] = to_offset( isodate.parse_duration(form["resolution"]) ).freqstr # Convert ISO period string to pandas frequency string return fn(*args, **kwargs)
def wrapper(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'values' from request." ) return invalid_method(request.method) if "value" in form: value_groups = [parse_as_list(form["value"], of_type=float)] elif "values" in form: value_groups = [parse_as_list(form["values"], of_type=float)] elif "groups" in form: value_groups = [] for group in form["groups"]: if "value" in group: value_groups.append(parse_as_list(group["value"], of_type=float)) elif "values" in group: value_groups.append(parse_as_list(group["values"], of_type=float)) else: current_app.logger.warning("Group %s missing value(s)" % group) return ptus_incomplete() else: current_app.logger.warning("Request missing value(s) or group.") return ptus_incomplete() if not contains_empty_items(value_groups): kwargs["value_groups"] = value_groups return fn(*args, **kwargs) else: extra_info = "Request includes empty or ill-formatted value(s)." current_app.logger.warning(extra_info) return ptus_incomplete(extra_info)
def wrapper(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'start' and 'duration' from request." ) return invalid_method(request.method) if "start" in form: start = parse_isodate_str(form["start"]) if not start: current_app.logger.warning("Cannot parse 'start' value") return invalid_period() if start.tzinfo is None: current_app.logger.warning("Cannot parse timezone of 'start' value") return invalid_timezone( "Start time should explicitly state a timezone." ) else: current_app.logger.warning("Request missing 'start'.") return invalid_period() kwargs["start"] = start if "duration" in form: duration = parse_duration(form["duration"], start) if not duration: current_app.logger.warning("Cannot parse 'duration' value") return invalid_period() else: current_app.logger.warning("Request missing 'duration'.") return invalid_period() kwargs["duration"] = duration return fn(*args, **kwargs)
def decorated_service(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'prior' from request." ) return invalid_method(request.method) if "prior" in form: prior = parse_isodate_str(form["prior"]) if ex_post is True: start = parse_isodate_str(form["start"]) duration = parse_duration(form["duration"], start) # todo: validate start and duration (refactor already duplicate code from period_required and optional_horizon_accepted) knowledge_time = ( start + duration ) # todo: take into account knowledge horizon function if prior < knowledge_time: extra_info = "Meter data can only be observed after the fact." return invalid_horizon(extra_info) elif infer_missing is True or ( infer_missing_play is True and current_app.config.get( "FLEXMEASURES_MODE", "") == "play"): # A missing prior is inferred by the server prior = server_now() else: # Otherwise, a missing prior is fine (a horizon may still be inferred by the server) prior = None kwargs["prior"] = prior return fn(*args, **kwargs)
def decorated_service(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'horizon' from request." ) return invalid_method(request.method) rolling = True if "horizon" in form: horizon, rolling = parse_horizon(form["horizon"]) if horizon is None: current_app.logger.warning("Cannot parse 'horizon' value") return invalid_horizon() elif ex_post is True: if horizon > timedelta(hours=0): extra_info = "Meter data must have a zero or negative horizon to indicate observations after the fact." return invalid_horizon(extra_info) elif infer_missing is True: # A missing horizon is only accepted if the server can infer it if "start" in form and "duration" in form: start = parse_isodate_str(form["start"]) duration = parse_duration(form["duration"], start) if not start: extra_info = "Cannot parse 'start' value." current_app.logger.warning(extra_info) return invalid_period(extra_info) if start.tzinfo is None: current_app.logger.warning( "Cannot parse timezone of 'start' value" ) return invalid_timezone( "Start time should explicitly state a timezone." ) if not duration: extra_info = "Cannot parse 'duration' value." current_app.logger.warning(extra_info) return invalid_period(extra_info) if current_app.config.get("FLEXMEASURES_MODE", "") == "play": horizon = timedelta(hours=0) else: horizon = start + duration - server_now() rolling = False else: current_app.logger.warning( "Request missing both 'horizon', 'start' and 'duration'." ) extra_info = "Specify a 'horizon' value, or 'start' and 'duration' values so that the horizon can be inferred." return invalid_horizon(extra_info) else: # Otherwise, a missing horizon is fine horizon = None kwargs["horizon"] = horizon if infer_missing is True: kwargs["rolling"] = rolling return fn(*args, **kwargs)
def decorated_service(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'type' from request." ) return invalid_method(request.method) elif "type" not in form: current_app.logger.warning("Request is missing message type.") return no_message_type() elif form["type"] != message_type: current_app.logger.warning("Type is not accepted for this endpoint.") return invalid_message_type(message_type) else: return fn(*args, **kwargs)
def wrapper(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'unit' from request." ) return invalid_method(request.method) if "unit" in form: unit = form["unit"] else: current_app.logger.warning("Request missing 'unit'.") return invalid_unit(quantity=None, units=None) kwargs["unit"] = unit return fn(*args, **kwargs)
def decorated_service(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'unit' from request." ) return invalid_method(request.method) elif "unit" not in form: current_app.logger.warning("Request is missing unit.") return invalid_unit(quantity, units) elif form["unit"] not in units: current_app.logger.warning( "Unit %s is not accepted as one of %s." % (form["unit"], units) ) return invalid_unit(quantity, units) else: kwargs["unit"] = form["unit"] return fn(*args, **kwargs)
def decorated_service(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking '%s' from request." % plural_name ) return invalid_method(request.method) if generic_asset_type_name in form: generic_asset_name_groups = [ parse_as_list(form[generic_asset_type_name]) ] elif plural_name in form: generic_asset_name_groups = [parse_as_list(form[plural_name])] elif groups_name in form: generic_asset_name_groups = [] for group in form["groups"]: if generic_asset_type_name in group: generic_asset_name_groups.append( parse_as_list(group[generic_asset_type_name]) ) elif plural_name in group: generic_asset_name_groups.append( parse_as_list(group[plural_name]) ) else: current_app.logger.warning( "Group %s missing %s" % (group, plural_name) ) return unrecognized_connection_group() else: current_app.logger.warning("Request missing %s or group." % plural_name) return unrecognized_connection_group() if not contains_empty_items(generic_asset_name_groups): kwargs["generic_asset_name_groups"] = generic_asset_name_groups return fn(*args, **kwargs) else: current_app.logger.warning("Request includes empty %s." % plural_name) return unrecognized_connection_group()
def decorated_service(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'source' from request." ) return invalid_method(request.method) if "source" in form: validated_user_source_ids = validate_user_sources( form["source"]) if None in validated_user_source_ids: return invalid_source(form["source"]) kwargs["user_source_ids"] = include_current_user_source_id( validated_user_source_ids) elif default_source is not None: kwargs["user_source_ids"] = include_current_user_source_id( validate_user_sources(default_source)) else: kwargs["user_source_ids"] = None return fn(*args, **kwargs)
def decorated_service(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for unpacking 'horizon' from request." ) return invalid_method(request.method) rolling = True if "horizon" in form: horizon, rolling = parse_horizon(form["horizon"]) if horizon is None: current_app.logger.warning("Cannot parse 'horizon' value") return invalid_horizon() elif ex_post is True: if horizon > timedelta(hours=0): extra_info = "Meter data must have a zero or negative horizon to indicate observations after the fact." return invalid_horizon(extra_info) elif rolling is True and accept_repeating_interval is False: extra_info = ( "API versions 2.0 and higher use regular ISO 8601 durations instead of repeating time intervals. " "For example: R/P1D should be replaced by P1D.") return invalid_horizon(extra_info) elif infer_missing is True or ( infer_missing_play is True and current_app.config.get( "FLEXMEASURES_MODE", "") == "play"): # A missing horizon is set to zero horizon = timedelta(hours=0) else: # Otherwise, a missing horizon is fine (a prior may still be inferred by the server) horizon = None kwargs["horizon"] = horizon if infer_missing is True and accept_repeating_interval is True: kwargs["rolling"] = rolling return fn(*args, **kwargs)
def decorated_service(*args, **kwargs): form = get_form_from_request(request) if form is None: current_app.logger.warning( "Unsupported request method for inferring resolution from request." ) return invalid_method(request.method) if not all( key in kwargs for key in [ "value_groups", "start", "duration", ] ): current_app.logger.warning("Could not infer resolution.") fields = ("values", "start", "duration") return required_info_missing(fields, "Resolution cannot be inferred.") if "generic_asset_name_groups" not in kwargs: return required_info_missing( (entity_type), "Required resolution cannot be found without asset info.", ) # Calculating (inferring) the resolution in the POSTed data inferred_resolution = ( (kwargs["start"] + kwargs["duration"]) - kwargs["start"] ) / len(kwargs["value_groups"][0]) # Finding the required resolution for assets affected in this request required_resolution = None last_asset = None for asset_group in kwargs["generic_asset_name_groups"]: for asset_descriptor in asset_group: # Getting the asset generic_asset = get_generic_asset(asset_descriptor, entity_type) if generic_asset is None: return unrecognized_asset( f"Failed to look up asset by {asset_descriptor}" ) # Complain if assets don't all require the same resolution if ( required_resolution is not None and generic_asset.event_resolution != required_resolution ): return conflicting_resolutions( f"Cannot send data for both {generic_asset} and {last_asset}." ) # Setting the resolution & remembering last looked-at asset required_resolution = generic_asset.event_resolution last_asset = generic_asset # if inferred resolution is a multiple from required_solution, we can upsample_values if inferred_resolution % required_resolution == timedelta(hours=0): for i in range(len(kwargs["value_groups"])): kwargs["value_groups"][i] = upsample_values( kwargs["value_groups"][i], from_resolution=inferred_resolution, to_resolution=required_resolution, ) inferred_resolution = required_resolution if inferred_resolution != required_resolution: current_app.logger.warning( f"Resolution {inferred_resolution} is not accepted. We require {required_resolution}." ) return unapplicable_resolution( isodate.duration_isoformat(required_resolution) ) else: kwargs["resolution"] = inferred_resolution return fn(*args, **kwargs)