Source code for aequilibrae.project.data.result_record

import pandas as pd
import json
import sqlite3
from typing import Optional

from aequilibrae.project.network.safe_class import SafeClass


[docs] class ResultRecord(SafeClass): """Class for handling records of results in the AequilibraE project database. This class provides methods to save, delete, and retrieve result records and their data. Arguments: **data_set** (:obj:`dict`): Dictionary containing the result record data. **project**: (:obj:`Project`): Project object this result record belongs to. **project_conn** (:obj:`Optional[sqlite3.Connection])`: Connection to the project database. If None, the project's connection will be used. **results_conn** (:obj:`Optional[sqlite3.Connection]`): Connection to the results database. If None, the project's results connection will be used. """ def __init__( self, data_set: dict, project, project_conn: Optional[sqlite3.Connection] = None, results_conn: Optional[sqlite3.Connection] = None, ): super().__init__(data_set, project) self._exists: bool self.__dict__["_exists"] = True self.__dict__["_project_conn"] = project_conn self.__dict__["_results_conn"] = results_conn
[docs] def save(self) -> None: """Saves results record to the project database. Creates a new record if it doesn't exist or updates an existing one. """ with self._project_conn or self.project.db_connection as conn: sql = "SELECT COUNT(*) FROM results WHERE table_name=?" if conn.execute(sql, [self.table_name]).fetchone()[0] == 0: data = [ str(self.table_name), str(self.procedure), str(self.procedure_id), self.procedure_report, str(self.timestamp), str(self.description), self.year, self.scenario, self.reference_table, ] conn.execute( "INSERT INTO results (table_name, procedure, procedure_id, procedure_report, timestamp, description, year, scenario, reference_table)" " VALUES(?,?,?,?,?,?,?,?,?)", data, ) for key, value in self.__dict__.items(): if key != "table_name" and key in self.__original__: v_old = self.__original__.get(key, None) if value != v_old and value: self.__original__[key] = value conn.execute(f"UPDATE results SET '{key}'=? WHERE table_name=?", [value, self.table_name])
[docs] def delete(self) -> None: """Deletes this results record and the underlying data from disk. Removes both the record from the project database and the data table from the results database. """ with ( self._project_conn or self.project.db_connection as project_conn, self._results_conn or self.project.results_connection as results_conn, ): project_conn.execute("DELETE FROM results WHERE table_name=?", [self.table_name]) results_conn.execute(f'DROP TABLE IF EXISTS "{self.table_name}"') self.__dict__["_exists"] = False
[docs] def get_data(self) -> pd.DataFrame: """Returns the results data for further computation. Returns: **df** (:obj:`pd.DataFrame`): DataFrame containing the results data. """ with self._results_conn or self.project.results_connection as conn: return pd.read_sql(f'SELECT * FROM "{self.table_name}"', conn)
[docs] def set_data(self, df: pd.DataFrame, **kwargs) -> None: """Set the results data corresponding to this record. Additionally saves this record. Additional keyword arguments forwarded to the ``pd.DataFrame.to_sql`` method. Arguments: **df** (:obj:`pd.DataFrame`): DataFrame object to save. Uses ``pd.DataFrame.to_sql``. """ self.save() with self._results_conn or self.project.results_connection as conn: df.to_sql(self.table_name, conn, **kwargs)
def __setattr__(self, instance, value) -> None: """Override attribute setting with validation. Validates table_name uniqueness and handles report serialisation. Arguments: **instance** (:obj:`str`): Attribute name. **value** (:obj:`object`): Value to set. Raises: ValueError: If trying to set a table_name that already exists. """ if instance == "table_name": with self._project_conn or self.project.db_connection as conn: sql = f"Select count(*) from results where {instance}=?" qry_value = sum(conn.execute(sql, [str(value)]).fetchone()) if qry_value > 0: raise ValueError("Another results with this table_name already exists") self.__dict__[instance] = value