diff --git a/calour/amplicon_experiment.py b/calour/amplicon_experiment.py index 95d5b5a5..17de670f 100644 --- a/calour/amplicon_experiment.py +++ b/calour/amplicon_experiment.py @@ -52,6 +52,9 @@ class AmpliconExperiment(Experiment): sparse : bool store the data array in :class:`scipy.sparse.csr_matrix` or :class:`numpy.ndarray` + databases: iterable of str, optional + database interface names to show by default in heatmap() function + by default use 'dbbact' Attributes ---------- @@ -70,15 +73,16 @@ class AmpliconExperiment(Experiment): information about the experiment (data md5, filenames, etc.) description : str name of the experiment - databases : iterable of str - databases for fetching and entering feature annotations + databases : dict + keys are the database names (i.e. 'dbbact' / 'gnps') + values are the database specific data for the experiment (i.e. annotations for dbbact) See Also -------- Experiment ''' def __init__(self, *args, databases=('dbbact',), **kwargs): - super().__init__(*args, databases=('dbbact',), **kwargs) + super().__init__(*args, databases=databases, **kwargs) def heatmap(self, *args, **kwargs): '''Plot a heatmap for the amplicon experiment. diff --git a/calour/calour.config b/calour/calour.config index ad0975bb..ed7b16a1 100644 --- a/calour/calour.config +++ b/calour/calour.config @@ -4,6 +4,7 @@ class_name = DBBact website = www.dbbact.org installation = pip install git+git://github.com/amnona/dbbact-calour description = manual annotations about bacterial amplicon sequences +min_version = 2020.0709 [sponge] module_name = spongeworld_calour diff --git a/calour/database.py b/calour/database.py index 16ffcfb5..8042d0b3 100644 --- a/calour/database.py +++ b/calour/database.py @@ -56,12 +56,14 @@ def _get_database_class(dbname, exp=None, config_file_name=None): ''' class_name = get_config_value('class_name', section=dbname, config_file_name=config_file_name) module_name = get_config_value('module_name', section=dbname, config_file_name=config_file_name) + min_version = float(get_config_value('min_version', section=dbname, config_file_name=config_file_name, fallback='0.0')) + module_website = get_config_value('website', section=dbname, config_file_name=config_file_name, fallback='NA') + if class_name is not None and module_name is not None: try: # import the database module db_module = importlib.import_module(module_name) except ImportError: - module_website = get_config_value('website', section=dbname, config_file_name=config_file_name) module_installation = get_config_value('installation', section=dbname, config_file_name=config_file_name) logger.warning('Database interface %s not installed.\nSkipping.\n' 'You can install the database using:\n%s\n' @@ -70,6 +72,11 @@ def _get_database_class(dbname, exp=None, config_file_name=None): # get the class DBClass = getattr(db_module, class_name) cdb = DBClass(exp) + # test if database version is compatible + if min_version > 0: + db_version = cdb.version() + if db_version < min_version: + logger.warning('Please update %s database module. Current version (%f) not supported (minimal version %f).\nFor details see %s' % (dbname, db_version, min_version, module_website)) return cdb # not found, so print available database names databases = [] diff --git a/calour/experiment.py b/calour/experiment.py index e8d0f508..ba4b553b 100644 --- a/calour/experiment.py +++ b/calour/experiment.py @@ -55,6 +55,8 @@ class Experiment: sparse : bool store the data array in :class:`scipy.sparse.csr_matrix` or :class:`numpy.ndarray` + databases: iterable of str, optional + database interface names to show by default in heatmap() function Attributes ---------- @@ -76,8 +78,9 @@ class Experiment: information about the experiment (data md5, filenames, etc.) description : str a short description of the experiment - databases : iterable of str - databases for fetching and entering feature annotations + databases : defaultdict(dict) + keys are the database names (i.e. 'dbbact' / 'gnps') + values are the database specific data for the experiment (i.e. annotations for dbbact) See Also -------- @@ -103,8 +106,10 @@ def __init__(self, data, sample_metadata, feature_metadata=None, databases=(), # flag if data array is sparse (True) or dense (False) self.sparse = sparse - # the default databases to use for feature information - self.databases = databases + # the database local specific data (to use for feature information) + self.databases = defaultdict(dict) + for cdatabase in databases: + self.databases[cdatabase] = {} def validate(self): '''Validate the Experiment object. diff --git a/calour/heatmap/heatmap.py b/calour/heatmap/heatmap.py index 287df77d..4e861426 100644 --- a/calour/heatmap/heatmap.py +++ b/calour/heatmap/heatmap.py @@ -546,7 +546,7 @@ def plot(exp: Experiment, title=None, ''' # set the databases if default requested if databases is None: - databases = exp.databases + databases = list(exp.databases.keys()) if tree is None: gui_obj = _create_plot_gui(exp, gui, databases) diff --git a/calour/heatmap/plotgui.py b/calour/heatmap/plotgui.py index db9a225e..ccdf5ced 100644 --- a/calour/heatmap/plotgui.py +++ b/calour/heatmap/plotgui.py @@ -75,8 +75,8 @@ class PlotGUI(ABC): Axes for the dendrogram/tree ax_legend : matplotlib.axes.Axes Axes for the color legend - databases : list - the databases to interact with + databases : list on None, optional + the databases to interact with. Parameters ---------- @@ -86,7 +86,8 @@ class PlotGUI(ABC): the scaling factor for zooming scroll_offset : float The amount of columns/rows to scroll when arrow key pressed - databases : the databases to interact with + databases : list of str or None + the databases to interact with. tree_size : int (>= 0) the width of the axes to plot a tree. 7 is a good value to start. diff --git a/calour/heatmap/plotgui_qt5.py b/calour/heatmap/plotgui_qt5.py index 6ee4ad14..62838a63 100644 --- a/calour/heatmap/plotgui_qt5.py +++ b/calour/heatmap/plotgui_qt5.py @@ -26,7 +26,8 @@ class PlotGUI_QT5(PlotGUI): figure : ``matplotlib.figure.Figure`` app : QT5 App created app_window : Windows belonging to the QT5 App - databases : + databases : list of str + The databases to interact with ''' @ds.with_indent(8) diff --git a/calour/tests/mock_database.py b/calour/tests/mock_database.py index ae7ea431..16c1914c 100644 --- a/calour/tests/mock_database.py +++ b/calour/tests/mock_database.py @@ -77,3 +77,8 @@ def get_feature_terms(self, features, exp=None): for cstr in cterms: feature_terms[cseq].append(cstr) return feature_terms + + def version(self): + '''return the current database version + ''' + return 2020.0709 diff --git a/calour/tests/test_database.py b/calour/tests/test_database.py index 6cac80fb..41ed068b 100644 --- a/calour/tests/test_database.py +++ b/calour/tests/test_database.py @@ -10,6 +10,7 @@ from os.path import join from tempfile import mkdtemp import shutil +import logging from calour._testing import Tests from calour.tests.mock_database import MockDatabase @@ -60,6 +61,20 @@ def test_get_database_class(self): shutil.rmtree(d) + def test_get_database_class_version(self): + d = mkdtemp() + f = join(d, 'config.txt') + calour.util.set_config_value('class_name', 'MockDatabase', section='testdb', config_file_name=f) + calour.util.set_config_value('module_name', 'calour.tests.mock_database', section='testdb', config_file_name=f) + calour.util.set_config_value('min_version', '9999.9999', section='testdb', config_file_name=f) + # re-enable logging because it is disabled in setUp + logging.disable(logging.NOTSET) + with self.assertLogs(level='WARNING') as cm: + db = _get_database_class('testdb', config_file_name=f) + self.assertEqual(db.database_name, 'mock_db') + self.assertRegex(cm.output[0], 'Please update') + shutil.rmtree(d) + if __name__ == "__main__": main()