def _make_schema( db_name: Optional[str] = None, ) -> Tuple[DatabaseConnector, Dict[str, Dict[str, str]]]: """ Create the schema (i.e. make all the tables) of the database. Parameters ---------- db_name : None or str Name of the database Returns ------- db_connector : DatabaseConnector The database connection object final_parameters_as_sql_types : dict Final parameters as sql types """ db_connector = make_test_database(db_name) default_parameters = get_default_parameters final_parameters = FinalParameters(default_parameters) final_parameters_dict = final_parameters.get_final_parameters() final_parameters_as_sql_types = final_parameters.cast_to_sql_type( final_parameters_dict ) db_creator = DatabaseCreator(db_connector) db_creator.create_all_schema_tables(final_parameters_as_sql_types) return db_connector, final_parameters_as_sql_types
def test_db_creator( make_test_database: Callable[[str], DatabaseConnector], make_test_schema: Callable[ [str], Tuple[DatabaseConnector, Dict[str, Dict[str, str]]] ], ) -> None: """ Test we can create the database schemas. Specifically this test that: 1. The database is empty on creation 2. The tables are created 3. It is not possible to create the schema more than once 4. Check that all expected tables have been created Parameters ---------- make_test_database : function Function returning the database connection make_test_schema : function Function returning the database connection and the final parameters as sql types """ db_connector_no_schema = make_test_database("test_creation_without_schema") db_reader_no_schema = DatabaseReader(db_connector_no_schema) # There should be no tables before creating them assert not db_reader_no_schema.check_tables_created() db_connector_schema, final_parameters_as_sql_types = make_test_schema( "test_creation_with_schema" ) db_reader_schema = DatabaseReader(db_connector_schema) db_creator = DatabaseCreator(db_connector_schema) # The tables should now have been created assert db_reader_schema.check_tables_created() with pytest.raises(sqlite3.OperationalError): db_creator.create_all_schema_tables(final_parameters_as_sql_types) # Check that all tables has been created non_parameter_tables = { "system_info", "split", "file_modification", "parameters", "run", } parameter_tables = set( el.replace(":", "_") for el in final_parameters_as_sql_types.keys() ) query_str = 'SELECT name FROM sqlite_master WHERE type="table"' table = db_reader_schema.query(query_str) actual = table.loc[:, "name"].values # pylint: disable=no-member assert non_parameter_tables.union(parameter_tables) == set(actual)
def __init__( self, executor: Optional[BoutRunExecutor] = None, db_connector: Optional[DatabaseConnector] = None, final_parameters: Optional[FinalParameters] = None, ) -> None: """ Set the member data. This constructor will also create the schema if it does not exist. Parameters ---------- executor : BoutRunExecutor or None Object executing the run If None, default parameters will be used db_connector : DatabaseConnector or None The connection to the database If None: Default database connector will be used final_parameters : FinalParameters or None The object containing the parameters which are going to be used in the run If None, default parameters will be used """ # Set member data # NOTE: We are not setting the default as a keyword argument # as this would mess up the paths logging.info("Start: Making a BoutRunSetup object") self.__executor = executor if executor is not None else BoutRunExecutor( ) self.__final_parameters = (final_parameters if final_parameters is not None else FinalParameters()) self.__db_connector = ( db_connector if db_connector is not None else DatabaseConnector( name=self.__executor.exec_name, db_root_path=self.__executor.bout_paths.project_path, )) self.__db_creator = DatabaseCreator(self.db_connector) self.__metadata_recorder = MetadataRecorder(self.__db_connector, self.executor.bout_paths, self.final_parameters) if not self.__metadata_recorder.db_reader.check_tables_created(): logging.info( "Creating schema as no tables were found in " "%s", self.__metadata_recorder.db_reader.db_connector.db_path, ) self.__create_schema() logging.info("Done: Making a BoutRunSetup object")
def test_get_create_table_statement() -> None: """Test that get_create_table_statement returns expected output.""" result = DatabaseCreator.get_create_table_statement( table_name="foo", columns=dict(bar="baz", foobar="qux"), primary_key="quux", foreign_keys=dict(quuz=("corge", "grault"), garply=("waldo", "fred")), ) expected = ( "CREATE TABLE foo \n" "( quux INTEGER PRIMARY KEY,\n" " bar baz NOT NULL,\n" " foobar qux NOT NULL,\n" " quuz INTEGER NOT NULL,\n" " garply INTEGER NOT NULL,\n" " FOREIGN KEY(quuz) \n" " REFERENCES corge(grault)\n" " ON UPDATE CASCADE\n" " ON DELETE CASCADE,\n" " FOREIGN KEY(garply) \n" " REFERENCES waldo(fred)\n" " ON UPDATE CASCADE\n" " ON DELETE CASCADE)" ) assert result == expected
class BoutRunSetup: """ Class for setting up the BOUT++ run. More specifically this class will connect the executor object with the run parameters and a database to store the results in Attributes ---------- __executor : BoutRunExecutor Getter variable for executor __db_connector : DatabaseConnector Getter variable for db_connector __final_parameters : FinalParameters Getter variable for final_parameters __db_creator : DatabaseCreator Object used to create the database __metadata_recorder : MetadataRecorder Object used to record the metadata about a run executor : BoutRunExecutor Object used to execute the run bout_paths : BoutPaths The BoutPaths obtained through the get property db_connector : DatabaseConnector Object containing the database connection final_parameters : FinalParameters Object containing the parameters to use metadata_recorder : MetadataRecorder Object containing the metadata recorder submitter : AbstractSubmitter The submitter obtained through the get property Methods ------- __create_schema() Create the schema Examples -------- >>> run_setup = BoutRunSetup(executor, db_connector, final_parameters) >>> run_graph = RunGraph() >>> run_group = RunGroup(run_graph, run_setup) >>> runner = BoutRunner(run_graph) >>> runner.run() """ def __init__( self, executor: Optional[BoutRunExecutor] = None, db_connector: Optional[DatabaseConnector] = None, final_parameters: Optional[FinalParameters] = None, ) -> None: """ Set the member data. This constructor will also create the schema if it does not exist. Parameters ---------- executor : BoutRunExecutor or None Object executing the run If None, default parameters will be used db_connector : DatabaseConnector or None The connection to the database If None: Default database connector will be used final_parameters : FinalParameters or None The object containing the parameters which are going to be used in the run If None, default parameters will be used """ # Set member data # NOTE: We are not setting the default as a keyword argument # as this would mess up the paths logging.info("Start: Making a BoutRunSetup object") self.__executor = executor if executor is not None else BoutRunExecutor( ) self.__final_parameters = (final_parameters if final_parameters is not None else FinalParameters()) self.__db_connector = ( db_connector if db_connector is not None else DatabaseConnector( name=self.__executor.exec_name, db_root_path=self.__executor.bout_paths.project_path, )) self.__db_creator = DatabaseCreator(self.db_connector) self.__metadata_recorder = MetadataRecorder(self.__db_connector, self.executor.bout_paths, self.final_parameters) if not self.__metadata_recorder.db_reader.check_tables_created(): logging.info( "Creating schema as no tables were found in " "%s", self.__metadata_recorder.db_reader.db_connector.db_path, ) self.__create_schema() logging.info("Done: Making a BoutRunSetup object") @property def executor(self) -> BoutRunExecutor: """ Get the properties of self.executor. Returns ------- self.__executor : BoutRunExecutor The executor object """ return self.__executor @property def bout_paths(self) -> BoutPaths: """ Return the BoutPaths. Returns ------- BoutPaths The BoutPaths """ return self.executor.bout_paths @property def final_parameters(self) -> FinalParameters: """ Get the properties of self.final_parameters. Returns ------- self.__final_parameters : FinalParameters The object containing the parameters used in the run """ return self.__final_parameters @property def db_connector(self) -> DatabaseConnector: """ Get the properties of self.db_connector. Returns ------- self.__db_connector : DatabaseConnector The object holding the database connection """ return self.__db_connector @property def metadata_recorder(self) -> MetadataRecorder: """ Get the properties of self.metadata_recorder. Returns ------- self.__metadata_recorder : MetadataRecorder The object holding the metadata recorder """ return self.__metadata_recorder @property def submitter(self) -> AbstractSubmitter: """ Return the AbstractSubmitter. Returns ------- AbstractSubmitter The submitter which will be used for submitting the job """ return self.executor.submitter def __create_schema(self) -> None: """Create the schema.""" final_parameters_dict = self.final_parameters.get_final_parameters() final_parameters_as_sql_types = self.final_parameters.cast_to_sql_type( final_parameters_dict) self.__db_creator.create_all_schema_tables( final_parameters_as_sql_types)