Пример #1
0
    def test_custom_calculated_field(self, field_name: str, scope_code: str, function_code: str, return_type: str) \
            -> Optional[Any]:
        from src.db_models import CalculatedField
        from src import configuration  # imports global configuration

        from src import configuration
        if not configuration.update_run_background or not self.current_status_raw:
            self.update_status()

        field = CalculatedField(
            id=-1,
            name=field_name,
            description="",
            return_type=return_type,
            calc_fn=function_code,
            scope_id=1  # TODO
        )
        current_item = {}

        # TODO generate current item and index based on the scope

        self._add_user_defined_calculated_field(
            field,
            current_item,
            initial_status=self.initial_status_raw,
            current_status=self.current_status_raw,
            position_list=self.car_positions_raw,
            lap_list=self.lap_list_raw,
            charging_process_list=self.charging_process_list_raw,
            total=self.total_raw,
            forecast=self.forecast_raw,
            current_item_index=None,
            configuration=configuration,
            now_dt=pendulum.now(tz='utc'))
        return current_item
Пример #2
0
    def _enhance_forecast(self,
                          forecast: Dict[str, Any],
                          dt: pendulum.DateTime,
                          *,
                          initial_status,
                          current_status,
                          position_list,
                          lap_list,
                          total,
                          charging_process_list,
                          _forecast=None,
                          configuration: Configuration) -> Dict[str, Any]:
        """
        Add calculated fields for forecast
        :param forecast:
        :return: the enhanced version (note it does in place enhancements, changes the parameter)
        """
        # add hardcoded calculated fields
        from src.data_processor.calculated_fields_forecast import add_calculated_fields
        add_calculated_fields(current_item=forecast,
                              initial_status=initial_status,
                              current_status=current_status,
                              position_list=position_list,
                              lap_list=lap_list,
                              total=total,
                              charging_process_list=charging_process_list,
                              forecast=forecast,
                              configuration=configuration,
                              current_item_index=None,
                              now_dt=dt)

        # add user-defined (db) calculated fields
        from src.db_models import CalculatedField
        db_calculated_fields = CalculatedField.get_all_by_scope(
            CalculatedFieldScopeEnum.FORECAST.value)
        for db_calculated_field in db_calculated_fields:
            self._add_user_defined_calculated_field(
                db_calculated_field,
                forecast,
                initial_status=initial_status,
                current_status=current_status,
                position_list=position_list,
                lap_list=lap_list,
                total=total,
                charging_process_list=charging_process_list,
                forecast=forecast,
                configuration=configuration,
                current_item_index=None,
                now_dt=dt)
        return forecast
Пример #3
0
    def _enhance_positions(
            self,
            positions: List[Dict[str, Any]],
            dt: pendulum.DateTime,
            *,
            initial_status,
            current_status,
            _position_list=None,
            lap_list,
            total,
            charging_process_list,
            forecast,
            configuration: Configuration) -> List[Dict[str, Any]]:
        # add calculated fields
        # !! note this operation is expensive as it runs on lot of records

        from src.data_processor.calculated_fields_positions import add_calculated_fields
        from src.db_models import CalculatedField
        db_calculated_fields = CalculatedField.get_all_by_scope(
            CalculatedFieldScopeEnum.POSITION.value)
        for i in range(len(positions)):
            add_calculated_fields(current_item=positions[i],
                                  initial_status=initial_status,
                                  current_status=current_status,
                                  position_list=positions,
                                  lap_list=lap_list,
                                  total=total,
                                  charging_process_list=charging_process_list,
                                  forecast=forecast,
                                  configuration=configuration,
                                  current_item_index=i,
                                  now_dt=dt)
            for field_description in db_calculated_fields:
                self._add_user_defined_calculated_field(
                    field_description,
                    positions[i],
                    initial_status=initial_status,
                    current_status=current_status,
                    position_list=positions,
                    lap_list=lap_list,
                    total=total,
                    charging_process_list=charging_process_list,
                    forecast=forecast,
                    configuration=configuration,
                    current_item_index=i,
                    now_dt=dt,
                )
        return positions
Пример #4
0
    def _enhance_laps(self,
                      laps: List[Dict[str, Any]],
                      dt: pendulum.DateTime,
                      *,
                      initial_status,
                      current_status,
                      position_list,
                      _lap_list=None,
                      total,
                      charging_process_list,
                      forecast,
                      configuration: Configuration) -> List[Dict[str, Any]]:

        from src.data_processor.calculated_fields_laps import add_calculated_fields
        from src.db_models import CalculatedField
        db_calculated_fields = CalculatedField.get_all_by_scope(
            CalculatedFieldScopeEnum.POSITION.value)
        for i in range(len(laps)):
            add_calculated_fields(current_item=laps[i],
                                  initial_status=initial_status,
                                  current_status=current_status,
                                  position_list=position_list,
                                  lap_list=laps,
                                  total=total,
                                  charging_process_list=charging_process_list,
                                  forecast=forecast,
                                  configuration=configuration,
                                  current_item_index=i,
                                  now_dt=dt)
            for field_description in db_calculated_fields:
                self._add_user_defined_calculated_field(
                    field_description,
                    laps[i],
                    initial_status=initial_status,
                    current_status=current_status,
                    position_list=position_list,
                    lap_list=laps,
                    total=total,
                    charging_process_list=charging_process_list,
                    forecast=forecast,
                    configuration=configuration,
                    current_item_index=i,
                    now_dt=dt,
                )
        return laps
Пример #5
0
 def _enhance_charging_processes(
         self, charging_processes: List[Dict[str, Any]],
         dt: pendulum.DateTime, *, initial_status, current_status,
         position_list, lap_list, total, forecast, _charging_process_list,
         configuration: Configuration) -> List[Dict[str, Any]]:
     """
     Add calculated fields for charigng processes
     :param forecast:
     :return: the enhanced version (note it does in place enhancements, changes the parameter)
     """
     from src.data_processor.calculated_fields_charges import add_calculated_fields
     from src.db_models import CalculatedField
     db_calculated_fields = CalculatedField.get_all_by_scope(
         CalculatedFieldScopeEnum.POSITION.value)
     for i in range(len(charging_processes)):
         add_calculated_fields(current_item=charging_processes[i],
                               initial_status=initial_status,
                               current_status=current_status,
                               position_list=position_list,
                               lap_list=lap_list,
                               total=total,
                               charging_process_list=charging_processes,
                               forecast=forecast,
                               configuration=configuration,
                               current_item_index=i,
                               now_dt=dt)
         for field_description in db_calculated_fields:
             self._add_user_defined_calculated_field(
                 field_description,
                 charging_processes[i],
                 initial_status=initial_status,
                 current_status=current_status,
                 position_list=position_list,
                 lap_list=lap_list,
                 total=total,
                 charging_process_list=charging_processes,
                 forecast=forecast,
                 configuration=configuration,
                 current_item_index=i,
                 now_dt=dt,
             )
     return charging_processes
Пример #6
0
def save_calculated_fields(field_scope_code: str,
                           req_data: CalculatedFieldApiList) -> int:
    from src import db

    field_scope: Optional[FieldScope] = FieldScope.query.filter_by(
        code=field_scope_code).first()

    if not field_scope:
        field_scope = FieldScope(code=field_scope_code, title=req_data.title)
        db.session.add(field_scope)
    else:
        field_scope.title = req_data.title
    db.session.commit()

    order_key = 1
    db_obj_list = []
    # transform to objects, add order key
    for item in req_data.items:
        db_obj = CalculatedField(**item.dict(),
                                 order_key=order_key,
                                 scope_id=field_scope.id)
        db_obj_list.append(db_obj)
        order_key += 1

    try:
        calculated_fields = CalculatedField.query.filter_by(
            scope_id=field_scope.id).all()
        # cleanup old records
        for cf in calculated_fields:
            db.session.delete(cf)
        db.session.commit()
        # write new records
        for obj in db_obj_list:
            db.session.add(obj)
        db.session.commit()
    except Exception as ex:
        db.session.rollback()
        raise ex
    return len(db_obj_list)
Пример #7
0
    def index(self):

        form = TestCalculatedFieldForm()
        from src import configuration, db
        from src.db_models import FieldScope, CalculatedField
        form.field_scope.choices = [(g.code, g)
                                    for g in FieldScope.query.all()]
        if form.validate_on_submit():
            try:
                return_value = data_processor.test_custom_calculated_field(
                    '__test_field__', form.field_scope.data, form.fn_code.data,
                    "")  # TODO the return type is not needed for now
                flash(
                    Markup(
                        f"Return value is <b>{return_value['__test_field__']}</b>"
                    ), "info")
                if form.add.data:
                    scope = FieldScope.query.filter_by(
                        code=form.field_scope.data).first()
                    cf_ok = CalculatedField.query.filter_by(
                        scope_id=scope.id).order_by(
                            CalculatedField.order_key.desc()).first()
                    order_key = 1
                    if cf_ok:
                        order_key = cf_ok.order_key + 1
                    cf = CalculatedField(name=form.name.data,
                                         description=form.description.data,
                                         return_type=form.return_type.data,
                                         calc_fn=form.fn_code.data,
                                         scope_id=scope.id,
                                         order_key=order_key)
                    try:
                        db.session.add(cf)
                        db.session.commit()
                        flash(
                            f"Calculated field {form.name.data} stored to database for code {form.field_scope.data}",
                            "info")
                    except Exception as ex:
                        db.session.rollback()
                        flash(f"Can't add {form.name.data}: {ex}", "error")
            except Exception as ex:
                flash(f"{type(ex).__name__}: {ex}", "error")
        laps = data_processor.get_laps_raw()
        lap = laps[-2 if len(laps) > 1 else -1]
        lap = {
            k: v
            for k, v in lap.items()
            if not isinstance(v, dict) and not isinstance(v, list)
        }
        return self.render(
            'admin/test_calculated_field.html',
            form=form,
            current_status=data_processor.get_status_raw(),
            position=data_processor.get_positions_raw()[-1],
            lap=lap,
            charging=data_processor.get_charging_process_list_raw()[-1],
            total=data_processor.get_total_raw(),
            forecast=data_processor.get_forecast_raw(),
            configuration=configuration.dict(),
            post_url=url_for('test_calculated_field.index'),
            with_categories=True)