Example #1
0
    def setUp(self):
        alchemist = AlchemyHandler()
        alchemist.username = "******"
        alchemist.password = "******"
        alchemist.database = "test_db"
        alchemist.connect()
        alchemist.build_graph()
        self.alchemist = alchemist

        self.db_filter = Filter(alchemist=self.alchemist)

        phageid = self.alchemist.get_column("phage.PhageID")
        self.phageid = phageid
Example #2
0
def main(unparsed_args_list):
    """Uses parsed args to run the entirety of the file export pipeline.

    :param unparsed_args_list: Input a list of command line args.
    :type unparsed_args_list: list[str]
    """
    #Returns after printing appropriate error message from parsing/connecting.
    args = parse_export(unparsed_args_list)

    alchemist = AlchemyHandler(database=args.database)
    alchemist.connect(ask_database=True, pipeline=True)
    alchemist.build_graph()

    # Exporting as a SQL file is not constricted by schema version.
    if args.pipeline != "sql":
        mysqldb.check_schema_compatibility(alchemist.engine, "export")

    values = []
    if args.pipeline in FILTERABLE_PIPELINES:
        values = parse_value_input(args.input)

    if not args.pipeline in PIPELINES:
        print("ABORTED EXPORT: Unknown pipeline option discrepency.\n"
              "Pipeline parsed from command line args is not supported")
        sys.exit(1)

    if args.pipeline != "I":
        execute_export(alchemist,
                       args.folder_path,
                       args.folder_name,
                       args.pipeline,
                       table=args.table,
                       values=values,
                       filters=args.filters,
                       groups=args.groups,
                       sort=args.sort,
                       include_columns=args.include_columns,
                       exclude_columns=args.exclude_columns,
                       sequence_columns=args.sequence_columns,
                       raw_bytes=args.raw_bytes,
                       concatenate=args.concatenate,
                       verbose=args.verbose)
    else:
        pass
Example #3
0
class TestAlchemyHandler(unittest.TestCase):
    def setUp(self):
        self.alchemist = AlchemyHandler()

    def test_constructor_1(self):
        self.assertEqual(self.alchemist._database, None)
        self.assertEqual(self.alchemist._username, None)
        self.assertEqual(self.alchemist._password, None)

    def test_constructor_2(self):
        self.assertEqual(self.alchemist._engine, None)
        self.assertEqual(self.alchemist.metadata, None)
        self.assertEqual(self.alchemist.graph, None)
        self.assertEqual(self.alchemist.session, None)

    def test_constructor_3(self):
        self.assertFalse(self.alchemist.connected)
        self.assertFalse(self.alchemist.has_database)
        self.assertFalse(self.alchemist.has_credentials)

    def test_database_1(self):
        self.alchemist.database = "Test"
        self.assertTrue(self.alchemist.has_database)
        self.assertFalse(self.alchemist.connected_database)

    def test_username_1(self):
        self.alchemist.username = "******"
        self.assertFalse(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)

    def test_username_2(self):
        self.alchemist.password = "******"
        self.alchemist.username = "******"
        self.assertTrue(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)

    def test_password_1(self):
        self.alchemist.password ="******"
        self.assertFalse(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)

    def test_password_2(self):
        self.alchemist.username = "******"
        self.alchemist.password = "******"
        self.assertTrue(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)
   
    def test_engine_1(self):
        self.alchemist.connected = True
        self.alchemist.engine = None

        self.assertFalse(self.alchemist.connected)
       
    def test_engine_2(self):
        with self.assertRaises(TypeError):
            self.alchemist.engine = "Test"

    @patch("pdm_utils.classes.alchemyhandler.input")
    def test_ask_database_1(self, Input):
        self.alchemist.ask_database()
        Input.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.input")
    def test_ask_database_2(self, Input):
        self.alchemist.has_database = False
        self.alchemist.connected = True

        self.alchemist.ask_database()
 
        self.assertTrue(self.alchemist.has_database)
        self.assertFalse(self.alchemist.connected)

    @patch("pdm_utils.classes.alchemyhandler.getpass")
    def test_ask_credentials_1(self, GetPass):
        self.alchemist.ask_credentials()

        GetPass.assert_called()
 
    @patch("pdm_utils.classes.alchemyhandler.getpass")
    def test_ask_credentials_2(self, GetPass):
        self.alchemist.has_credentials = False
        self.alchemist.connected = True

        self.alchemist.ask_credentials()

        self.assertTrue(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)

    
    def test_validate_database_1(self):
        MockEngine = Mock()
        MockProxy = Mock()

        MockEngine.execute.return_value = MockProxy 
        MockProxy.fetchall.return_value = [("test_db",), 
                                           ("Actinobacteriophage",)]
 
        self.alchemist.database = "test_db"
        self.alchemist._engine = MockEngine

        self.alchemist.validate_database()

        MockEngine.execute.assert_called_with("SHOW DATABASES")
        MockProxy.fetchall.assert_called()

    def test_validate_database_2(self):
        with self.assertRaises(IndexError):
            self.alchemist.validate_database()

    def test_validate_database_3(self):
        MockEngine = Mock()
        MockProxy = Mock()

        MockEngine.execute.return_value = MockProxy
        MockProxy.fetchall.return_value = []

        self.alchemist.database = "test db"
        self.alchemist._engine = MockEngine

        with self.assertRaises(ValueError):
            self.alchemist.validate_database()

        MockEngine.execute.assert_called_with("SHOW DATABASES")
        MockProxy.fetchall.assert_called()


    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
                                                        "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.sqlalchemy.create_engine")
    def test_build_engine_1(self, CreateEngine, AskCredentials):
        self.alchemist.engine = None
        self.alchemist.connected = True
        self.alchemist.build_engine()

        CreateEngine.assert_not_called()
        AskCredentials.assert_not_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
                                                        "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.sqlalchemy.create_engine")
    def test_build_engine_2(self, CreateEngine, AskCredentials):
        self.alchemist.username = "******"
        self.alchemist.password = "******"
        self.alchemist.has_credentials = False

        self.alchemist.build_engine()

        AskCredentials.assert_called()
        login_string = "mysql+pymysql://user:pass@localhost/"
        CreateEngine.assert_called_with(login_string)
   
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.validate_database")
    @patch("pdm_utils.classes.alchemyhandler.sqlalchemy.create_engine")
    def test_build_engine_3(self, CreateEngine, ValidateDatabase): 
        self.alchemist.username = "******"
        self.alchemist.password = "******"
        self.alchemist.database = "database"

        self.alchemist.build_engine()

        login_string = "mysql+pymysql://user:pass@localhost/"
        db_login_string = "mysql+pymysql://user:pass@localhost/database"

        CreateEngine.assert_any_call(login_string)
        CreateEngine.assert_any_call(db_login_string)

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
                                                        "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.sqlalchemy.create_engine")
    def test_build_engine_4(self, CreateEngine, AskCredentials):
        self.alchemist.has_credentials = True
        self.alchemist.connected = False
        self.alchemist.metadata = "Test"
        self.alchemist.graph = "Test"

        self.alchemist.build_engine()

        self.alchemist.connected = True
        self.assertEqual(self.alchemist.metadata, None)
        self.assertEqual(self.alchemist.graph, None)

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
                                                        "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    def test_connect_1(self, BuildEngine, AskDatabase, AskCredentials):
        self.alchemist.has_credentials = True
        self.alchemist.connect()
        BuildEngine.assert_called()
        AskDatabase.assert_not_called()
        AskCredentials.assert_not_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
                                                        "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    def test_connect_2(self, BuildEngine, AskDatabase, AskCredentials):
        self.alchemist.connect(ask_database=True)
        BuildEngine.assert_called()
        AskDatabase.assert_called()
        AskCredentials.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
                                                        "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    def test_connect_3(self, BuildEngine, AskDatabase, AskCredentials):
        self.alchemist.connected = False
        BuildEngine.side_effect = OperationalError("", "", "")
        
        with self.assertRaises(ValueError):
            self.alchemist.connect()

        BuildEngine.assert_called()
        AskDatabase.assert_not_called()
        AskCredentials.assert_called()

    def mock_build_engine(self, mock_engine):
        self.alchemist._engine = mock_engine

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    def test_execute_1(self, BuildEngine):
        MockEngine = Mock()
        MockProxy  = Mock()

        MockEngine.execute.return_value = MockProxy 
        MockProxy.fetchall.return_value = []

        self.alchemist._engine = MockEngine

        self.alchemist.execute("Executable")

        MockEngine.execute.assert_called_with("Executable")
        MockProxy.fetchall.assert_called()
        BuildEngine.assert_not_called() 
   
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    def test_scalar_1(self, BuildEngine):
        MockEngine = Mock()
        MockProxy  = Mock()
        
        MockEngine.execute.return_value = MockProxy
        MockProxy.scalar.return_value = "Scalar"

        self.alchemist._engine = MockEngine
       
        self.alchemist.scalar("Executable")

        MockEngine.execute.assert_called_with("Executable")
        MockProxy.scalar.assert_called()
        BuildEngine.assert_not_called()

    @patch("pdm_utils.classes.alchemyhandler.MetaData")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    def test_build_metadata_1(self, AskDatabase, BuildEngine, MetaData):
        self.alchemist.has_database = False
        self.alchemist.connected = False

        self.alchemist.build_metadata()

        AskDatabase.assert_called()
        BuildEngine.assert_called()
        MetaData.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.MetaData")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    def test_build_metadata_2(self, AskDatabase, BuildEngine, MetaData):
        self.alchemist.has_database = True
        self.alchemist.connected = True
        
        self.alchemist.build_metadata()

        AskDatabase.assert_not_called()
        BuildEngine.assert_not_called()
        MetaData.assert_called() 

    @patch("pdm_utils.classes.alchemyhandler.parsing.translate_table")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_translate_table_1(self, BuildMetadata, TranslateTable):
        self.alchemist.metadata = "Metadata"

        self.alchemist.translate_table("Test")

        TranslateTable.assert_called_with("Metadata", "Test")
        BuildMetadata.assert_not_called()

    @patch("pdm_utils.classes.alchemyhandler.parsing.translate_table")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_translate_table_2(self, BuildMetadata, TranslateTable):
        self.alchemist.metadata = None

        self.alchemist.translate_table("Test")

        TranslateTable.assert_called_with(None, "Test")
        BuildMetadata.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.parsing.translate_column") 
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_translate_column_1(self, BuildMetadata, TranslateColumn):
        self.alchemist.metadata = "Metadata"

        self.alchemist.translate_column("Test")

        TranslateColumn.assert_called_with("Metadata", "Test")
        BuildMetadata.assert_not_called()

    @patch("pdm_utils.classes.alchemyhandler.parsing.translate_column") 
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_translate_column_2(self, BuildMetadata, TranslateColumn):
        self.alchemist.metadata = None

        self.alchemist.translate_column("Test")

        TranslateColumn.assert_called_with(None, "Test")
        BuildMetadata.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.querying.get_table")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_get_table_1(self, BuildMetadata, GetTable):
        self.alchemist.metadata = "Metadata"

        self.alchemist.get_table("Test")

        GetTable.assert_called_with("Metadata", "Test")
        BuildMetadata.assert_not_called()

    @patch("pdm_utils.classes.alchemyhandler.querying.get_table")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_get_table_2(self, BuildMetadata, GetTable):
        self.alchemist.metadata = None

        self.alchemist.get_table("Test")

        GetTable.assert_called_with(None, "Test")
        BuildMetadata.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.querying.get_column") 
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_get_column_1(self, BuildMetadata, GetColumn):
        self.alchemist.metadata = "Metadata"

        self.alchemist.get_column("Test")

        GetColumn.assert_called_with("Metadata", "Test")
        BuildMetadata.assert_not_called()
        
    @patch("pdm_utils.classes.alchemyhandler.querying.get_column") 
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_get_column_2(self, BuildMetadata, GetColumn):
        self.alchemist.metadata = None

        self.alchemist.get_column("Test")

        GetColumn.assert_called_with(None, "Test")
        BuildMetadata.assert_called()
 
    @patch("pdm_utils.classes.alchemyhandler.querying.build_graph")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_build_graph_1(self, BuildMetadata, BuildGraph):
        BuildGraph.return_value = "Graph"

        self.alchemist.metadata = "Metadata"

        self.alchemist.build_graph()

        BuildMetadata.assert_not_called()
        BuildGraph.assert_called_with("Metadata")
        
        self.assertEqual(self.alchemist.graph, "Graph")

    @patch("pdm_utils.classes.alchemyhandler.querying.build_graph")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_build_graph_2(self, BuildMetadata, BuildGraph):
        BuildGraph.return_value = "Graph"

        self.alchemist.metadata = None

        self.alchemist.build_graph()

        BuildMetadata.assert_called()
        BuildGraph.assert_called_with(None)
        
        self.assertEqual(self.alchemist.graph, "Graph")

    @patch("pdm_utils.classes.alchemyhandler.cartography.get_map")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_get_map_1(self, BuildMetadata, GetMap): 
        self.alchemist.metadata = "Metadata"

        self.alchemist.get_map("Test")

        BuildMetadata.assert_not_called()
        GetMap.assert_called_with("Metadata", "Test")

    @patch("pdm_utils.classes.alchemyhandler.cartography.get_map")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_get_map_2(self, BuildMetadata, GetMap):
        self.alchemist.metadata = None

        self.alchemist.get_map("Test")

        BuildMetadata.assert_called()
        GetMap.assert_called_with(None, "Test") 
Example #4
0
class TestAlchemyHandler(unittest.TestCase):
    def setUp(self):
        self.alchemist = AlchemyHandler()

    def test_constructor_1(self):
        """Verify AlchemyHandler credentials are initialized as None.
        """
        self.assertEqual(self.alchemist._database, None)
        self.assertEqual(self.alchemist._username, None)
        self.assertEqual(self.alchemist._password, None)

    def test_constructor_2(self):
        """Verify AlchemyHandler data objects are initialized as None.
        """
        self.assertEqual(self.alchemist._engine, None)
        self.assertEqual(self.alchemist._metadata, None)
        self.assertEqual(self.alchemist._graph, None)
        self.assertEqual(self.alchemist._session, None)

    def test_constructor_3(self):
        """Verify AlchemyHandler data booleans are initialized as False.
        """
        self.assertFalse(self.alchemist.connected)
        self.assertFalse(self.alchemist.has_database)
        self.assertFalse(self.alchemist.has_credentials)

    def test_database_1(self):
        """Verify database property sets has_database.
        """
        self.alchemist.database = "Test"
        self.assertTrue(self.alchemist.has_database)
        self.assertFalse(self.alchemist.connected_database)

    def test_username_1(self):
        """Verify username property conserves has_credentials and connected.
        """
        self.alchemist.username = "******"
        self.assertFalse(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)

    def test_username_2(self):
        """Verify username property sets has_credentials with valid password.
        """
        self.alchemist.password = "******"
        self.alchemist.username = "******"
        self.assertTrue(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.clear")
    def test_username_3(self, clear_mock):
        """Verify changing usrename property calls clear().
        """
        self.alchemist.username = "******"

        clear_mock.assert_called()

    def test_password_1(self):
        """Verify password property conserves has_credentials and connected.
        """
        self.alchemist.password = "******"
        self.assertFalse(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)

    def test_password_2(self):
        """Verify password property sets has_credentials with valid username.
        """
        self.alchemist.username = "******"
        self.alchemist.password = "******"
        self.assertTrue(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.clear")
    def test_password_3(self, clear_mock):
        """Verify changing password property calls clear().
        """
        self.alchemist.password = "******"

        clear_mock.assert_called()

    def test_construct_engine_string_1(self):
        """Verify construct_engine_string generates an expected URI.
        """
        URI = self.alchemist.construct_engine_string(username="******",
                                                     password="******")
        self.assertEqual(URI, "mysql+pymysql://pdm_user:pdm_pass@localhost/")

    def test_construct_engine_string_2(self):
        """Verify construct_engine_string accepts use of different drivers.
        """
        URI = self.alchemist.construct_engine_string(driver="mysqlconnector",
                                                     username="******",
                                                     password="******")

        self.assertEqual(URI,
                         "mysql+mysqlconnector://pdm_user:pdm_pass@localhost/")

    def test_engine_1(self):
        """Verify engine property sets connected.
        """
        self.alchemist.connected = True
        self.alchemist.engine = None

        self.assertFalse(self.alchemist.connected)

    def test_engine_2(self):
        """Verify engine property raises TypeError on bad engine input.
        """
        with self.assertRaises(TypeError):
            self.alchemist.engine = "Test"

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    def test_engine_3(self, build_engine_mock):
        """Verify engine property calls build_engine() selectively.
        """
        mock_engine = Mock()
        build_engine_mock.return_value = mock_engine

        self.alchemist._engine = "Test"
        self.assertEqual(self.alchemist.engine, "Test")

        build_engine_mock.assert_not_called()

        self.alchemist._engine = None
        self.alchemist.engine

        build_engine_mock.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler"
           ".extract_engine_credentials")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.get_mysql_dbs")
    def test_engine_4(self, get_mysql_dbs_mock,
                      extract_engine_credentials_mock):
        """Verify call structure of engine property setter.
        """
        mock_engine = Mock(spec=Engine)

        self.alchemist.engine = mock_engine

        get_mysql_dbs_mock.assert_called()
        extract_engine_credentials_mock.assert_called_with(mock_engine)

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_metadata_1(self, build_metadata_mock):
        """Verify metadata property calls build_metadata() selectively.
        """
        self.alchemist._metadata = "Test"
        self.alchemist.metadata

        build_metadata_mock.assert_not_called()

        self.alchemist._metadata = None
        self.alchemist.metadata

        build_metadata_mock.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_graph")
    def test_graph_1(self, build_graph_mock):
        """Verify graph property calls build_graph() selectively.
        """
        self.alchemist._graph = "Test"
        self.alchemist.graph

        build_graph_mock.assert_not_called()

        self.alchemist._graph = None
        self.alchemist.graph

        build_graph_mock.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_session")
    def test_session_1(self, build_session_mock):
        """Verify session property calls build_session() selectively.
        """
        self.alchemist._session = "Test"
        self.alchemist.session

        build_session_mock.assert_not_called()

        self.alchemist._session = None
        self.alchemist.session

        build_session_mock.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_mapper")
    def test_mapper_1(self, build_mapper_mock):
        """Verify mapper property calls build_mapper() selectively.
        """
        self.alchemist._mapper = "Test"
        self.alchemist.mapper

        build_mapper_mock.assert_not_called()

        self.alchemist._mapper = None
        self.alchemist.mapper

        build_mapper_mock.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.input")
    def test_ask_database_1(self, Input):
        """Verify ask_database() calls input().
        """
        self.alchemist.ask_database()
        Input.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.input")
    def test_ask_database_2(self, Input):
        """Verify ask_database() sets has_database.
        """
        self.alchemist.has_database = False
        self.alchemist.connected = True

        self.alchemist.ask_database()

        self.assertTrue(self.alchemist.has_database)
        self.assertFalse(self.alchemist.connected)

    @patch("pdm_utils.classes.alchemyhandler.getpass")
    def test_ask_credentials_1(self, GetPass):
        """Verify ask_credentials() calls getpass().
        """
        self.alchemist.ask_credentials()

        GetPass.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.getpass")
    def test_ask_credentials_2(self, GetPass):
        """Verify ask_credentials() sets has_credentials.
        """
        self.alchemist.has_credentials = False
        self.alchemist.connected = True

        self.alchemist.ask_credentials()

        self.assertTrue(self.alchemist.has_credentials)
        self.assertFalse(self.alchemist.connected)

    def test_validate_database_1(self):
        """Verify function structure of validate_database().
        """
        mock_engine = Mock()
        mock_proxy = Mock()

        mock_engine.execute.return_value = mock_proxy
        mock_proxy.fetchall.return_value = [("pdm_test_db",),
                                            ("Actinobacteriophage",)]

        self.alchemist.connected = True
        self.alchemist.database = "pdm_test_db"
        self.alchemist._engine = mock_engine

        self.alchemist.validate_database()

        mock_engine.execute.assert_called_once()
        mock_proxy.fetchall.assert_called()

    def test_validate_database_2(self):
        """Verify validate_database() raises IndexError without database.
        """
        self.alchemist.connected = True

        with self.assertRaises(AttributeError):
            self.alchemist.validate_database()

    def test_validate_database_3(self):
        """Verify validate_database() raises ValueError from bad database input.
        """
        mock_engine = Mock()
        mock_proxy = Mock()

        mock_engine.execute.return_value = mock_proxy
        mock_proxy.fetchall.return_value = []

        self.alchemist.connected = True
        self.alchemist.database = "test db"
        self.alchemist._engine = mock_engine

        with self.assertRaises(MySQLDatabaseError):
            self.alchemist.validate_database()

        mock_engine.execute.assert_called_once()
        mock_proxy.fetchall.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
           "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.sqlalchemy.create_engine")
    def test_build_engine_1(self, create_engine_mock, ask_credentials_mock):
        """Verify build_engine() returns if connected already.
        """
        self.alchemist.engine = None
        self.alchemist.connected = True
        self.alchemist.build_engine()

        create_engine_mock.assert_not_called()
        ask_credentials_mock.assert_not_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
           "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.sqlalchemy.create_engine")
    def test_build_engine_2(self, create_engine_mock, ask_credentials_mock):
        """Verify build_engine() raises attribute error without credentials.
        """
        self.alchemist.username = "******"
        self.alchemist.password = "******"
        self.alchemist.has_credentials = False

        with self.assertRaises(AttributeError):
            self.alchemist.build_engine()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.validate_database")
    @patch("pdm_utils.classes.alchemyhandler.sqlalchemy.create_engine")
    def test_build_engine_3(self, create_engine_mock, validate_database_mock):
        """Verify build_engine() calls create_engine() with db engine string.
        """
        self.alchemist.username = "******"
        self.alchemist.password = "******"
        self.alchemist.database = "database"

        self.alchemist.build_engine()

        login_string = "mysql+pymysql://user:pass@localhost/"
        db_login_string = "mysql+pymysql://user:pass@localhost/database"

        create_engine_mock.assert_any_call(login_string, echo=False)
        create_engine_mock.assert_any_call(db_login_string, echo=False)

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
           "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.sqlalchemy.create_engine")
    def test_build_engine_4(self, create_engine_mock, ask_credentials_mock):
        """Verify build_engine() sets has_credentials.
        """
        self.alchemist.has_credentials = True
        self.alchemist.connected = False
        self.alchemist._metadata = "Test"
        self.alchemist._graph = "Test"

        self.alchemist.build_engine()

        self.alchemist.connected = True
        self.assertEqual(self.alchemist._metadata, None)
        self.assertEqual(self.alchemist._graph, None)

    @patch("pdm_utils.classes.alchemyhandler.sqlalchemy.create_engine")
    def test_build_engine_5(self, create_engine_mock):
        """Verify AlchemyHandler echo property controls create_engine()
        parameters.
        """
        self.alchemist.username = "******"
        self.alchemist.password = "******"
        self.alchemist.build_engine()

        login_string = "mysql+pymysql://user:pass@localhost/"

        create_engine_mock.assert_any_call(login_string, echo=False)

        self.alchemist.echo = True
        self.alchemist.connected = False
        self.alchemist.build_engine()

        create_engine_mock.assert_any_call(login_string, echo=True)

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
           "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    def test_connect_1(self, build_engine_mock, ask_database_mock,
                       AskCredentials):
        """Verify connect() returns if build_engine() does not complain.
        """
        self.alchemist.has_credentials = True
        self.alchemist.connected = True
        self.alchemist.connect()
        build_engine_mock.assert_called()
        ask_database_mock.assert_not_called()
        AskCredentials.assert_not_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
           "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    def test_connect_2(self, build_engine_mock, ask_database_mock,
                       AskCredentials):
        """Verify connect() AlchemyHandler properties control function calls.
        """
        self.alchemist.connected = True
        self.alchemist.connected_database = True
        self.alchemist.has_credentials = True
        self.alchemist.connect(ask_database=True)
        build_engine_mock.assert_called()
        ask_database_mock.assert_not_called()
        AskCredentials.assert_not_called()

    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler."
           "ask_credentials")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    def test_connect_3(self, build_engine_mock, ask_database_mock,
                       AskCredentials):
        """Verify connect() depends on build_engine() to raise ValueError.
        """
        self.alchemist.connected = False
        build_engine_mock.side_effect = OperationalError("", "", "")

        with self.assertRaises(SQLCredentialsError):
            self.alchemist.connect()

        build_engine_mock.assert_called()
        ask_database_mock.assert_not_called()
        AskCredentials.assert_called()

    def build_engine_side_effect(self, mock_engine):
        """Helper function for side effect usage.
        """
        self.alchemist._engine = mock_engine

    @patch("pdm_utils.classes.alchemyhandler.MetaData")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    def test_build_metadata_1(self, ask_database_mock, build_engine_mock,
                              metadata_mock):
        """Verify build_metadata() relies on AlchemyHandler properties.
        """
        self.alchemist.has_database = False
        self.alchemist.connected = False

        self.alchemist.build_metadata()

        ask_database_mock.assert_called()
        build_engine_mock.assert_called()
        metadata_mock.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.MetaData")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    def test_build_metadata_2(self, ask_database_mock, build_engine_mock,
                              metadata_mock):
        """Verify build_metadata() calls ask_database() and build_engine().
        """
        self.alchemist.has_database = True
        self.alchemist.connected = True
        self.alchemist.connected_database = True

        self.alchemist.build_metadata()

        ask_database_mock.assert_not_called()
        build_engine_mock.assert_not_called()
        metadata_mock.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.querying.build_graph")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_build_graph_1(self, build_metadata_mock, build_graph_mock):
        """Verify build_graph() calls querying.build_graph().
        """
        build_graph_mock.return_value = "Graph"

        self.alchemist._metadata = "Metadata"

        self.alchemist.build_graph()

        build_metadata_mock.assert_not_called()
        build_graph_mock.assert_called_with("Metadata")

        self.assertEqual(self.alchemist._graph, "Graph")

    @patch("pdm_utils.classes.alchemyhandler.querying.build_graph")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_build_graph_2(self, build_metadata_mock, build_graph_mock):
        """Verify build_graph() calls build_metadata().
        """
        build_graph_mock.return_value = "Graph"

        self.alchemist._metadata = None

        self.alchemist.build_graph()

        build_metadata_mock.assert_called()
        build_graph_mock.assert_called_with(None)

        self.assertEqual(self.alchemist._graph, "Graph")

    @patch("pdm_utils.classes.alchemyhandler.sessionmaker")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    def test_build_session_1(self, ask_database_mock, build_engine_mock,
                             sessionmaker_mock):
        """Verify build_session() relies on AlchemyHandler properties.
        """
        self.alchemist.has_database = False
        self.alchemist.connected = False

        self.alchemist.build_session()

        ask_database_mock.assert_called()
        build_engine_mock.assert_called()
        sessionmaker_mock.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.sessionmaker")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_engine")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.ask_database")
    def test_build_session_2(self, ask_database_mock, build_engine_mock,
                             sessionmaker_mock):
        """Verify build_session() calls ask_database() and build_engine().
        """
        self.alchemist.has_database = True
        self.alchemist.connected = True

        self.alchemist.build_session()

        ask_database_mock.assert_not_called()
        build_engine_mock.assert_not_called()
        sessionmaker_mock.assert_called()

    @patch("pdm_utils.classes.alchemyhandler.automap_base")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_build_mapper_1(self, build_metadata_mock, automap_base_mock):
        """Verify build_mapper() calls automap_base().
        """
        base_mock = Mock()
        automap_base_mock.return_value = base_mock

        self.alchemist._metadata = "Metadata"

        self.alchemist.build_mapper()

        build_metadata_mock.assert_not_called()
        automap_base_mock.assert_called_with(metadata="Metadata")

        self.assertEqual(self.alchemist._mapper, base_mock)

    @patch("pdm_utils.classes.alchemyhandler.automap_base")
    @patch("pdm_utils.classes.alchemyhandler.AlchemyHandler.build_metadata")
    def test_build_mapper_2(self, build_metadata_mock, automap_base_mock):
        """Verify build_mapper() calls build_metadata().
        """
        base_mock = Mock()
        automap_base_mock.return_value = base_mock

        self.alchemist._metadata = None

        self.alchemist.build_mapper()

        build_metadata_mock.assert_called()
        automap_base_mock.assert_called_with(metadata=None)

        self.assertEqual(self.alchemist._mapper, base_mock)
Example #5
0
class TestFileExport(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        test_db_utils.create_filled_test_db()

        self.test_dir = Path(TEST_DIR)
        if self.test_dir.is_dir():
            shutil.rmtree(TEST_DIR)

        self.test_dir.mkdir()

    @classmethod
    def tearDownClass(self):
        test_db_utils.remove_db()
        shutil.rmtree(TEST_DIR)

    def setUp(self):
        self.alchemist = AlchemyHandler()
        self.alchemist.username=USER
        self.alchemist.password=PWD
        self.alchemist.database=DB
        self.alchemist.connect(ask_database=True, login_attempts=0)
        self.alchemist.build_graph()

        self.db_filter = Filter(alchemist=self.alchemist)
        
        self.export_test_dir = self.test_dir.joinpath("export_test_dir")

    def tearDown(self):
        if self.export_test_dir.is_dir():
            shutil.rmtree(str(self.export_test_dir))

    def test_execute_export_1(self):
        """Verify execute_export() creates new directory as expected.
        """
        for pipeline in export_db.PIPELINES:
            with self.subTest(pipeline=pipeline):
                export_db.execute_export(self.alchemist, self.test_dir, 
                                         self.export_test_dir.name, pipeline)
                self.assertTrue(self.export_test_dir.is_dir())
                shutil.rmtree(str(self.export_test_dir))

    def test_execute_export_2(self):
        """Verify execute_export() 'sql' pipeline functions as expected.
        """
        export_db.execute_export(self.alchemist, self.test_dir,
                                  self.export_test_dir.name, "sql")

        self.assertTrue(self.export_test_dir.is_dir())
        
        sql_file_path = self.export_test_dir.joinpath(
                                            f"{self.alchemist.database}.sql")
        self.assertTrue(sql_file_path.is_file())

    def test_execute_export_3(self):
        """Verify execute_export() 'csv' pipeline functions as expected.
        """
        for table in export_db.TABLES:
            with self.subTest(table=table):
                export_db.execute_export(self.alchemist, self.test_dir,
                                          self.export_test_dir.name, "csv",
                                          table=table)
                self.assertTrue(self.export_test_dir.is_dir())

                csv_file_path = self.export_test_dir.joinpath(
                                            f"{table}.csv")

                self.assertTrue(csv_file_path.is_file())

                shutil.rmtree(str(self.export_test_dir))

    def test_execute_export_4(self):
        """Verify execute_export() SeqRecord pipelines function as expected.
        """
        for file_type in export_db.BIOPYTHON_PIPELINES:
            with self.subTest(file_type=file_type):
                export_db.execute_export(self.alchemist, self.test_dir,
                                         self.export_test_dir.name, file_type)
                self.assertTrue(self.export_test_dir.is_dir())

                flat_file_path = self.export_test_dir.joinpath(
                                            f"Trixie.{file_type}")
                self.assertTrue(flat_file_path.is_file())

                shutil.rmtree(str(self.export_test_dir))
   
    def test_execute_export_5(self):
        """Verify execute_export() filter parameter functions as expected.
        """
        filters = "phage.PhageID!=Trixie AND phage.Cluster=A"
        export_db.execute_export(self.alchemist, self.test_dir,
                                 self.export_test_dir.name, "fasta",
                                 filters=filters)

        D29_file_path = self.export_test_dir.joinpath("D29.fasta")
        Trixie_file_path = self.export_test_dir.joinpath("Trixie.fasta")

        self.assertTrue(D29_file_path.is_file())
        self.assertFalse(Trixie_file_path.is_file())
    
    def test_execute_export_6(self):
        """Verify execute_export() group parameter functions as expected.
        """
        groups = ["phage.Cluster", "phage.Subcluster"]
        export_db.execute_export(self.alchemist, self.test_dir,
                                 self.export_test_dir.name, "fasta",
                                 groups=groups)

        A_path = self.export_test_dir.joinpath("A")
        C_path = self.export_test_dir.joinpath("C")

        A2_path = A_path.joinpath("A2")
        C1_path = C_path.joinpath("C1")
        C2_path = C_path.joinpath("C2")

        Trixie_path = A2_path.joinpath("Trixie.fasta")
        D29_path = A2_path.joinpath("D29.fasta")
        Alice_path = C1_path.joinpath("Alice.fasta")
        Myrna_path = C2_path.joinpath("Myrna.fasta")

                            
        self.assertTrue(A_path.is_dir())
        self.assertTrue(C_path.is_dir())

        self.assertTrue(A2_path.is_dir())
        self.assertTrue(C1_path.is_dir())
        self.assertTrue(C2_path.is_dir())

        self.assertTrue(Trixie_path.is_file())
        self.assertTrue(D29_path.is_file())
        self.assertTrue(Alice_path.is_file())
        self.assertTrue(Myrna_path.is_file())
        
    def test_execute_export_7(self):
        """Verify execute_export() sort parameter is functional.
        """
        sort_columns = ["phage.Subcluster"]
        export_db.execute_export(self.alchemist, self.test_dir,
                                 self.export_test_dir.name, "csv",
                                 sort=sort_columns)
    
    def test_execute_export_8(self):
        """Verify execute_export() concatenate parameter functions as expected.
        """
        export_db.execute_export(self.alchemist, self.test_dir,
                                 self.export_test_dir.name, "fasta",
                                 concatenate=True)

        fasta_path = self.export_test_dir.joinpath(
                                        f"{self.export_test_dir.name}.fasta")

        self.assertTrue(fasta_path.is_file())

    def test_execute_export_9(self):
        """Verify execute_export() include_columns functions as expected.
        """
        include_columns = ["phage.Cluster"]
        export_db.execute_export(self.alchemist, self.test_dir,
                                 self.export_test_dir.name, "csv", table="gene",
                                 include_columns=include_columns)

        csv_path = self.export_test_dir.joinpath(
                                        f"gene.csv")

        with open(csv_path) as csv_handle:
            reader = csv.reader(csv_handle)
            headers = next(reader)

        self.assertTrue("Cluster" in headers)
        self.assertEqual("GeneID", headers[0])
        self.assertFalse("Translation" in headers)
    
    def test_execute_export_10(self):
        """Verify execute_export() exclude_columns functions as expected.
        """
        exclude_columns = ["phage.Subcluster"]
        export_db.execute_export(self.alchemist, self.test_dir,
                                 self.export_test_dir.name, "csv",
                                 exclude_columns=exclude_columns)
        
        csv_path = self.export_test_dir.joinpath(
                                        f"phage.csv")

        with open(csv_path) as csv_handle:
            reader = csv.reader(csv_handle)
            headers = next(reader)

        self.assertTrue("Cluster" in headers)
        self.assertEqual("PhageID", headers[0])
        self.assertFalse("Subcluster" in headers)
        self.assertFalse("Sequence" in headers)

    def test_execute_export_11(self):
        """Verify execute_export() sequence_columns functions as expected.
        """
        export_db.execute_export(self.alchemist, self.test_dir,
                                 self.export_test_dir.name, "csv",
                                 sequence_columns=True)

        csv_path = self.export_test_dir.joinpath(
                                        f"phage.csv")

        with open(csv_path) as csv_handle:
            reader = csv.reader(csv_handle)
            headers = next(reader)

        self.assertTrue("Cluster" in headers)
        self.assertEqual("PhageID", headers[0])
        self.assertTrue("Sequence" in headers)

    def test_execute_export_12(self):
        """Verify execute_export() SeqRecord pipeline functions as expected.
        """
        for file_type in export_db.BIOPYTHON_PIPELINES:
            with self.subTest(file_type=file_type):
                export_db.execute_export(self.alchemist, self.test_dir,
                                         self.export_test_dir.name, file_type,
                                         table="gene")

                self.assertTrue(self.export_test_dir.is_dir())

                flat_file_path = self.export_test_dir.joinpath(
                                            f"Trixie_CDS_70.{file_type}")
                self.assertTrue(flat_file_path.is_file())

                shutil.rmtree(str(self.export_test_dir))
Example #6
0
class TestFileIO(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        base_dir = Path(TMPDIR_BASE)
        self.test_dir = base_dir.joinpath(TMPDIR_PREFIX)
        test_db_utils.create_filled_test_db()

        if self.test_dir.is_dir():
            shutil.rmtree(self.test_dir)

        self.test_dir.mkdir()

        self.test_import_table_1 = Path(test_file_dir,
                                        "test_import_table_1.csv")
        self.tkt_dict1 = {"phage_id": "L5", "host_genus": "Mycobacterium"}
        self.tkt_dict2 = {"phage_id": "Trixie", "host_genus": "Mycobacterium"}

        self.test_fasta_file_1 = Path(test_file_dir, "test_fasta_file_1.fasta")
        self.test_fasta_file_2 = Path(test_file_dir, "test_fasta_file_2.fasta")

        self.test_fa_1_gs_to_ts = {}
        self.test_fa_2_gs_to_ts = {}
        with self.test_fasta_file_1.open(mode="r") as filehandle:
            for record in SeqIO.parse(filehandle, "fasta"):
                self.test_fa_1_gs_to_ts[record.id] = str(record.seq)
                self.test_fa_2_gs_to_ts[record.id] = str(record.seq)

        self.test_fa_1_ts_to_gs = {}
        for seq_id, trans in self.test_fa_1_gs_to_ts.items():
            seq_ids = self.test_fa_1_ts_to_gs.get(trans, [])
            seq_ids.append(seq_id)
            self.test_fa_1_ts_to_gs[trans] = seq_ids

        self.test_fa_2_ts_to_gs = {}
        for seq_id, trans in self.test_fa_2_gs_to_ts.items():
            seq_ids = self.test_fa_2_ts_to_gs.get(trans, [])
            seq_ids.append(seq_id)
            self.test_fa_2_ts_to_gs[trans] = seq_ids

        self.fasta_dict_1 = {
            "Trixie_CDS_11": ("MASIQGKLIALVLKYGISYLRKHPELLKEI"
                              "SKHIPGKVDDLVLEVLAKLLGV")
        }
        self.fasta_dict_2 = {
            "TRIXIE_CDS_3": ("MSGFDDKIVDQAQAIVPADDYDALPLAGPGR"
                             "WAHVPGGLTLYTNDDTVLFAQGDMSTIESSY"
                             "LFQAMEKLRLAGKTASQAFDILRLEADAISG"
                             "DLSELAEE"),
            "L5_CDS_3": ("MAQMQATHTIEGFLAVEVAPRAFVAENGHVL"
                         "TRLSATKWGGGEGLEILNYEGPGTVEVSDEK"
                         "LAEAQRASEVEAELRREVGKE")
        }

    @classmethod
    def tearDownClass(self):
        test_db_utils.remove_db()
        shutil.rmtree(self.test_dir)

    def setUp(self):
        self.alchemist = AlchemyHandler()
        self.alchemist.username = USER
        self.alchemist.password = PWD
        self.alchemist.database = DB
        self.alchemist.connect(ask_database=True, login_attempts=0)
        self.alchemist.build_graph()

        self.fileio_test_dir = self.test_dir.joinpath("fileio_test_dir")
        self.fileio_test_dir.mkdir()
        self.data_dict_file = self.fileio_test_dir.joinpath("table.csv")
        self.fasta_file = self.fileio_test_dir.joinpath("translations.fasta")

    def tearDown(self):
        shutil.rmtree(self.fileio_test_dir)

    def test_retrieve_data_dict_1(self):
        """Verify a correctly structured file can be opened."""
        list_of_data_dicts = \
            fileio.retrieve_data_dict(self.test_import_table_1)
        self.assertEqual(len(list_of_data_dicts), 2)

    def test_export_data_dict_1(self):
        """Verify data is exported correctly."""

        list_of_data = [self.tkt_dict1, self.tkt_dict2]
        headers = ["type", "phage_id", "host_genus", "cluster"]
        fileio.export_data_dict(list_of_data,
                                self.data_dict_file,
                                headers,
                                include_headers=True)

        exp_success_tkts = []
        with open(self.data_dict_file, 'r') as file:
            file_reader = csv.DictReader(file)
            for dict in file_reader:
                exp_success_tkts.append(dict)

        with self.subTest():
            self.assertEqual(len(exp_success_tkts), 2)
        with self.subTest():
            self.assertEqual(set(exp_success_tkts[0].keys()), set(headers))

    def test_write_fasta_1(self):
        """Verify write_fasta() creates readable fasta formatted file"""
        fileio.write_fasta(self.fasta_dict_1, self.fasta_file)

        record = SeqIO.read(self.fasta_file, "fasta")
        id = list(self.fasta_dict_1.keys())[0]
        seq = self.fasta_dict_1[id]

        self.assertEqual(record.id, id)
        self.assertEqual(str(record.seq), seq)

    def test_write_fasta_2(self):
        """Verify write_fasta() can properly concatenate fasta files"""
        fileio.write_fasta(self.fasta_dict_2, self.fasta_file)

        records = SeqIO.parse(self.fasta_file, "fasta")

        keys = list(self.fasta_dict_2.keys())

        for record in records:
            self.assertTrue(record.id in keys)

            seq = self.fasta_dict_2[record.id]
            self.assertEqual(str(record.seq), seq)

    def test_reintroduce_fasta_duplicates_1(self):
        """Verify reintroduce_duplicates() copies fastas without duplicates"""
        fileio.write_fasta(self.test_fa_1_gs_to_ts, self.fasta_file)

        fileio.reintroduce_fasta_duplicates(self.test_fa_1_ts_to_gs,
                                            self.fasta_file)

        with self.fasta_file.open(mode="r") as filehandle:
            for record in SeqIO.parse(filehandle, "fasta"):
                with self.subTest(seq_id=record.id):
                    translation = self.test_fa_1_gs_to_ts[record.id]
                    self.assertTrue(translation is not None)
                    self.assertEqual(str(record.seq), translation)

    def test_reintroduce_fasta_duplicates_2(self):
        """Verify reintroduce_duplicates() recognizes duplicate sequences"""
        fileio.write_fasta(self.test_fa_1_gs_to_ts, self.fasta_file)

        fileio.reintroduce_fasta_duplicates(self.test_fa_2_ts_to_gs,
                                            self.fasta_file)

        with self.fasta_file.open(mode="r") as filehandle:
            for record in SeqIO.parse(filehandle, "fasta"):
                with self.subTest(seq_id=record.id):
                    translation = self.test_fa_2_gs_to_ts[record.id]
                    self.assertTrue(translation is not None)
                    self.assertEqual(str(record.seq), translation)

    def test_reintroduce_fasta_duplicates_3(self):
        """Verify reintroduce_duplicates() preserves unrecognized translations
        """
        fileio.write_fasta(self.test_fa_2_gs_to_ts, self.fasta_file)

        fileio.reintroduce_fasta_duplicates(self.test_fa_1_ts_to_gs,
                                            self.fasta_file)

        with self.fasta_file.open(mode="r") as filehandle:
            for record in SeqIO.parse(filehandle, "fasta"):
                with self.subTest(seq_id=record.id):
                    translation = self.test_fa_2_gs_to_ts[record.id]
                    self.assertTrue(translation is not None)
                    self.assertEqual(str(record.seq), translation)