Repository: WrightonLabCSU/DRAM (language: python)

Issue:
Change all FTP URLs to HTTP(s) to avoid firewall/ACL issues
Here is a commit that changes all the FTP URLs to HTTP(s).


Discussion / hints:

Fix patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 9926b60c..5fba8362 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -8,14 +8,12 @@ version: 2.1
 jobs:
   build-and-test:
     docker:
-      - image: ubuntu:focal
+      - image: cimg/base:2022.09
     steps:
       - checkout
       - run:
           name: Setup Miniconda
           command: |
-            apt update
-            apt install -y wget
             cd $HOME
             wget -q https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh
             export MINICONDA_PREFIX="$HOME/miniconda"
@@ -27,22 +25,29 @@ jobs:
             conda config --add channels conda-forge
             conda info -a
       - run:
-          name: Run tests in enviroment
+          name: More conda stuff
           # This assumes pytest is installed via the install-package step above
           command: |
             export PATH="$HOME/miniconda/bin:$PATH"
             conda update -y conda
             conda create -n DRAM python=3.9
             source activate DRAM
-            conda install  pandas pytest pandas pytest scikit-bio scipy<=1.8.1 prodigal mmseqs2!=10.6d92c hmmer!=3.3.1 trnascan-se >=2 sqlalchemy barrnap altair >=4 openpyxl networkx ruby parallel dram
-            pytest tests/test_annotate_bins.py
-            pytest tests/test_annotate_vgfs.py
-            pytest tests/test_database_handler.py
-            pytest tests/test_database_processing.py
-            pytest tests/test_database_setup.py
-            pytest tests/test_summarize_genomes.py
-            pytest tests/test_summarize_vgfs.py
-            pytest tests/test_utils.py
+            conda install pandas pytest pandas pytest scikit-bio scipy==1.8.1 prodigal mmseqs2!=10.6d92c hmmer!=3.3.1 trnascan-se>=2 sqlalchemy barrnap altair>=4 openpyxl networkx ruby parallel pip
+            pip3 install ./
+      - run:
+          name: Run tests in enviroment
+          # This assumes pytest is installed via the install-package step above
+          command: |
+            source $HOME/miniconda/bin/activate DRAM
+            pytest
+            # pytest tests/test_annotate_bins.py
+            # pytest tests/test_annotate_vgfs.py
+            # pytest tests/test_database_handler.py
+            # pytest tests/test_database_processing.py
+            # pytest tests/test_database_setup.py
+            # pytest tests/test_summarize_genomes.py
+            # pytest tests/test_summarize_vgfs.py
+            # pytest tests/test_utils.py
 # Invoke jobs via workflows
 workflows:
   all-tests:
diff --git a/README.md b/README.md
index 3b0816c0..a2823508 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,81 @@
 # DRAM
 [![CircleCI](https://circleci.com/gh/WrightonLabCSU/DRAM/tree/master.svg?style=svg)](https://circleci.com/gh/WrightonLabCSU/DRAM/tree/master)
 
-DRAM (Distilled and Refined Annotation of Metabolism) is a tool for annotating metagenomic assembled genomes and [VirSorter](https://github.com/simroux/VirSorter) identified viral contigs. DRAM annotates MAGs and viral contigs using [KEGG](https://www.kegg.jp/) (if provided by the user), [UniRef90](https://www.uniprot.org/), [PFAM](https://pfam.xfam.org/), [dbCAN](http://bcb.unl.edu/dbCAN2/), [RefSeq viral](https://www.ncbi.nlm.nih.gov/genome/viruses/), [VOGDB](http://vogdb.org/) and the [MEROPS](https://www.ebi.ac.uk/merops/) peptidase database as well as custom user databases. DRAM is run in two stages. First an annotation step to assign database identifiers to gene and then a distill step to curate these annotations into useful functional categories. Additionally viral contigs are further analyzed during to identify potential AMGs. This is done via assigning an auxiliary score and flags representing the confidence that a gene is both metabolic and viral.
+DRAM (Distilled and Refined Annotation of Metabolism) is a tool for annotating metagenomic assembled genomes and [VirSorter](https://github.com/simroux/VirSorter) identified viral contigs. DRAM annotates MAGs and viral contigs using [KEGG](https://www.kegg.jp/) (if provided by the user), [UniRef90](https://www.uniprot.org/), [PFAM](https://pfam.xfam.org/), [dbCAN](http://bcb.unl.edu/dbCAN2/), [RefSeq viral](https://www.ncbi.nlm.nih.gov/genome/viruses/), [VOGDB](http://vogdb.org/) and the [MEROPS](https://www.ebi.ac.uk/merops/) peptidase database as well as custom user databases. DRAM is run in two stages. First an annotation step to assign database identifiers to gene, and then a distill step to curate these annotations into useful functional categories. Additionally, viral contigs are further analyzed during to identify potential AMGs. This is done via assigning an auxiliary score and flags representing the confidence that a gene is both metabolic and viral.
 
 For more detail on DRAM and how DRAM works please see our [paper](https://academic.oup.com/nar/article/48/16/8883/5884738) as well as the [wiki](https://github.com/shafferm/DRAM/wiki).
+For information on how DRAM is changing, please read the [release note](https://github.com/WrightonLabCSU/DRAM/releases/latest)
 
-## Installation
-To install DRAM some dependencies need to be installed first then DRAM can be installed from this repository. In the future DRAM will be available from conda. Dependencies can be installed via conda or manually.
-    
+## Getting Started Part 1: Installation
+
+**NOTE** If you already have an old release of DRAM installed and just want to upgrade, then please read the set-up step before you remove your old environment.
+
+To install DRAM you also must install some dependencies. The easiest way to install both DRAM and its dependencies is to use [conda](https://docs.conda.io/en/latest/miniconda.html),  but you can also use manual instructions, or if you are an adventurer you can install a release candidate from this repository .
+   
 _Conda Installation_
 
-Install DRAM into a new [conda](https://docs.conda.io/en/latest/) environment using the provided 
+Install DRAM into a new [conda](https://docs.conda.io/en/latest/) environment using the provided
 environment.yaml file.
 ```bash
 wget https://raw.githubusercontent.com/shafferm/DRAM/master/environment.yaml
 conda env create -f environment.yaml -n DRAM
 ```
-If this installation method is used then all further steps should be run inside the newly created DRAM environment. This environment can be activated using this command:
+If this installation method is used, then all further steps should be run inside the newly created DRAM environment, or with the full path to the executable, use `which` with the environment active to find these, the eg. `which DRAM.py`. This environment can be activated using this command:
 ```bash
 conda activate DRAM
 ```
 
+You have now installed DRAM, and are ready to set up the databases.
+
 _Manual Installation_
 
 If you do not install via a conda environment, then the dependencies [pandas](https://pandas.pydata.org/), [networkx](https://networkx.github.io/), [scikit-bio](http://scikit-bio.org/), [prodigal](https://github.com/hyattpd/Prodigal), [mmseqs2](https://github.com/soedinglab/mmseqs2), [hmmer](http://hmmer.org/) and [tRNAscan-SE](http://lowelab.ucsc.edu/tRNAscan-SE/) need to be installed manually. Then you can install DRAM using pip:
 ```bash
 pip install DRAM-bio
 ```
-Alternatively if you would like to install a development version of DRAM then you can install DRAM by cloning this repository and install using pip and the local repository.
 
-You have now installed DRAM.
+You have now installed DRAM, and are ready to set up the databases.
+
+_Release Candidate Installation_
+
+The latest version of DRAM is often a release candidate, and these are not pushed to pypi, or Bioconda and so can't be installed with the methods above. You can tell if there is currently a release candidate by reading the [release note](https://github.com/WrightonLabCSU/DRAM/releases/latest).
+
+To install a potentially unstable release candidate, follow the instructions below. Note the comments within the code sections as there is a context in which commands must be used.
+
+```bash
+# Clone the git repository and move into it
+git clone https://github.com/WrightonLabCSU/DRAM.git
+cd DRAM
+# Install dependencies, this will also install a stable version of DRAM that will then be replaced.
+conda env create --name my_dram_env -f environment.yaml
+conda activate my_dram_env
+# Install pip
+conda install pip3
+pip3 install ./
+```
+
+You have now installed DRAM, and are ready to set up the databases.
+
 
-## Setup
+## Getting Started Part 2: Setup Databases
 
-To run DRAM you need to set up the required databases in order to get annotations. All databases except for KEGG can be downloaded and set up for use with DRAM for you automatically. In order to get KEGG gene annotations and you must have access to the KEGG database. KEGG is a paid subscription service to download the protein files used by this annotator. If you do not have access to KEGG then DRAM will automatically use the [KOfam](https://www.genome.jp/tools/kofamkoala/) HMM database to get KEGG Orthology identifiers.
+_I Want to Use an Already Setup Databases_
+
+If you already installed and set up a previous version of dram and want to use your old databases, then you can do it with two steps.
+
+Activate your old DRAM environment, and save your old config:
+
+```bash
+conda activate my_old_env
+DRAM-setup.py export_config > my_old_config.txt
+```
+
+Activate your new DRAM environment, and import your old databases
+
+```bash
+conda activate my_new_env
+DRAM-setup.py import_config --config_loc  my_old_config.txt
+```
 
 _I have access to KEGG_
 
@@ -56,26 +98,26 @@ DRAM-setup.py prepare_databases --output_dir DRAM_data
 Similar to above you can still provide locations of databases you have already downloaded so you don't have to do it
 again.
 
-To test that your set up worked use the command `DRAM-setup.py print_config` and the location of all databases provided 
+To test that your set up worked use the command `DRAM-setup.py print_config` and the location of all databases provided
 will be shown as well as the presence of additional annotation information.
 
-*NOTE:* Setting up DRAM can take a long time (up to 5 hours) and uses a large about of memory (512 gb) by default. To
+*NOTE:* Setting up DRAM can take a long time (up to 5 hours) and uses a large amount of memory (512 gb) by default. To
 use less memory you can use the `--skip_uniref` flag which will reduce memory usage to ~64 gb if you do not provide KEGG
- Genes and 128 gb if you do. Depending on the number of processors which you tell  it to use (using the `--threads` 
+ Genes and 128 gb if you do. Depending on the number of processors which you tell  it to use (using the `--threads`
 argument) and the speed of your internet connection. On a less than 5 year old server with 10 processors it takes about
  2 hours to process the data when databases do not need to be downloaded.
 
-## Usage
+## Getting Started Part 3: Usage
 
-Once DRAM is set up you are ready to annotate some MAGs. The following command will generate your full annotation: 
+Once DRAM is set up you are ready to annotate some MAGs. The following command will generate your full annotation:
 
 ```bash
 DRAM.py annotate -i 'my_bins/*.fa' -o annotation
 ```
 
-`my_bins` should be replaced with the path to a directory which contains all of your bins you would like to annotated and `.fa` should be replaced with the file extension used for your bins (i.e. `.fasta`, `.fna`, etc). If you only need to annotated a single genome (or an entire assembly) a direct path to a nucleotide fasta should be provided. Using 20 processors DRAM.py takes about 17 hours to annotate ~80 MAGs of medium quality or higher from a mouse gut metagenome.
+`my_bins` should be replaced with the path to a directory which contains all of your bins you would like to annotated and `.fa` should be replaced with the file extension used for your bins (i.e. `.fasta`, `.fna`, etc). If you only need to annotate a single genome (or an entire assembly) a direct path to a nucleotide fasta should be provided. Using 20 processors, DRAM.py takes about 17 hours to annotate ~80 MAGs of medium quality or higher from a mouse gut metagenome.
 
-In the output `annotation` folder there will be various files. `genes.faa` and `genes.fna` are fasta files with all genes called by prodigal with additional header information gained from the annotation as nucleotide and amino acid records respectively. `genes.gff` is a GFF3 with the same annotation information as well as gene locations. `scaffolds.fna` is a collection of all scaffolds/contigs given as input to `DRAM.py annotate` with added bin information in the headers. `annotations.tsv` is the most important output of the annotation. This includes all annotation information about every gene from all MAGs. Each line is a different gene and each column contains annotation information. `trnas.tsv` contains a summary of the tRNAs found in each MAG.
+In the output `annotation` folder, there will be various files. `genes.faa` and `genes.fna` are fasta files with all genes called by prodigal with additional header information gained from the annotation as nucleotide and amino acid records respectively. `genes.gff` is a GFF3 with the same annotation information as well as gene locations. `scaffolds.fna` is a collection of all scaffolds/contigs given as input to `DRAM.py annotate` with added bin information in the headers. `annotations.tsv` is the most important output of the annotation. This includes all annotation information about every gene from all MAGs. Each line is a different gene and each column contains annotation information. `trnas.tsv` contains a summary of the tRNAs found in each MAG.
 
 Then after your annotation is finished you can summarize these annotations with the following command:
 
@@ -85,15 +127,17 @@ DRAM.py distill -i annotation/annotations.tsv -o genome_summaries --trna_path an
 This will generate the distillate and liquor files.
 
 ## System Requirements
-DRAM has a large memory burden and is designed to be run on high performance computers. DRAM annotates against a large 
-variety of databases which must be processed and stored. Setting up DRAM with KEGG Genes and UniRef90 will take up ~500 
-GB of storage after processing and require ~512 GB of RAM while using KOfam and skipping UniRef90 will mean all 
-processed databases will take up ~30 GB on disk and will only use ~128 GB of RAM while processing. DRAM annotation 
-memory usage depends on the databases used. When annotating with UniRef90 around 220 GB of RAM is required. If the KEGG 
-gene database has been provided and UniRef90 is not used then memory usage is around 100 GB of RAM. If KOfam is used to 
-annotate KEGG and UniRef90 is not used then less than 50 GB of RAM is required. DRAM can be run with any number of 
+DRAM has a large memory burden and is designed to be run on high performance computers. DRAM annotates against a large
+variety of databases which must be processed and stored. Setting up DRAM with KEGG Genes and UniRef90 will take up ~500
+GB of storage after processing and require ~512 GB of RAM while using KOfam and skipping UniRef90 will mean all
+processed databases will take up ~30 GB of disk and will only use ~128 GB of RAM while processing. DRAM annotation
+memory usage depends on the databases used. When annotating with UniRef90, around 220 GB of RAM is required. If the KEGG
+gene database has been provided and UniRef90 is not used, then memory usage is around 100 GB of RAM. If KOfam is used to
+annotate KEGG and UniRef90 is not used, then less than 50 GB of RAM is required. DRAM can be run with any number of
 processors on a single node.
 
 ## Citing DRAM
-The DRAM was published in Nucleic Acids Research in 2020 and is availabe [here](https://academic.oup.com/nar/article/48/16/8883/5884738). If 
-DRAM helps you out in your research please cite it.
+The DRAM was published in Nucleic Acids Research in 2020 and is available [here](https://academic.oup.com/nar/article/48/16/8883/5884738). If
+DRAM helps you out in your research, please cite it.
+
+
diff --git a/data/function_heatmap_form.tsv b/data/function_heatmap_form.tsv
index 033e2a79..429ff81d 100644
--- a/data/function_heatmap_form.tsv
+++ b/data/function_heatmap_form.tsv
@@ -1,81 +1,81 @@
 category	subcategory	function_name	function_ids	long_function_name	gene_symbol
-CAZy	CAZy	Polyphenolics	K05909, AA1, AA2, K00422	Polyphenolics Cleavage
-CAZy	CAZy	Crystalline Cellulose	GH7, GH48, AA10, AA15, AA16, AA9, AA10, AA11, AA13	Crystalline Cellulose Backbone Cleavage
-CAZy	CAZy	Amorphous Cellulose	GH5, GH6, GH7, GH8, GH9, GH10, GH124, GH12, GH44, GH45	Amorphous Cellulose Backbone Cleavage
-CAZy	CAZy	Amorphous Cellulose	GH94, GH1, GH2, GH3, GH5, GH9, GH16, GH116	Amorphous Cellulose Oligo Cleavage
-CAZy	CAZy	Mucin	GH101	Mucin Backbone Cleavage
-CAZy	CAZy	Mucin	GH27, GH129, GH112, GH109, GH31, GH36	Mucin Oligo Cleavage
-CAZy	CAZy	Sulf-Polysachharides	GH111, GH16, GH82, GH150, GH79, PL29, PL30, PL33, PL8, PL12, PL13, PL15, PL21, PL6, PL37, GH56, GH86	Sulf-Polysachharides Backbone Cleavage
-CAZy	CAZy	Sulf-Polysachharides	PL21, PL37, PL23, PL24, PL25, GH88, PL15, PL6, GH117	Sulf-Polysachharides Oligo Cleavage
-CAZy	CAZy	Xyloglucan	GH5, GH9, GH12, GH16, GH44, GH45, GH48, GH74, AA9	Xyloglucan Backbone Cleavage (Hemicellulose)
-CAZy	CAZy	Xyloglucan	GH31, GH43, GH10, GH2	Xyloglucan Oligo Cleavage (Hemicellulose)
-CAZy	CAZy	Starch	AA13, GH13, GH14, GH57, GH119, GH126	Starch Backbone Cleavage
-CAZy	CAZy	Starch	GH133, GH15, GH97	Starch Oligo Cleavage
-CAZy	CAZy	Chitin	GH18, GH19, GH23, GH73	Chitin Backbone Cleavage
-CAZy	CAZy	Chitin	GH20, GH3, GH5, GH84, GH116, AA10, AA11, AA15, CE4	Chitin Oligo Cleavage
-CAZy	CAZy	Pectin	GH28, PL1, PL2, PL9, PL10, PL11, PL22, PL26, PL3, PL4	Pectin Backbone Cleavage
-CAZy	CAZy	Pectin	GH78, GH106, GH138, GH139, GH143, CE8, GH105, GH4, CE12, GH2	Pectin Oligo Cleavage
-CAZy	CAZy	Alpha-galactans	GH166	Alpha-galactans Backbone Cleavage
-CAZy	CAZy	Alpha-galactans	GH27, GH110, GH4, GH31, GH36, GH97	Alpha-galactans Oligo Cleavage
-CAZy	CAZy	Beta-galactan (pectic galactan)	GH53	Beta-galactan (pectic galactan) Backbone Cleavage
-CAZy	CAZy	Beta-galactan (pectic galactan)	GH2, GH35, GH42, GH1, GH59, GH147, GH165	Beta-galactan (pectic galactan) Oligo Cleavage
-CAZy	CAZy	Mixed-Linkage glucans	GH16, GH30, GH17, GH7, GH8, GH9, GH5, GH55, GH64, GH81, GH128, GH152, GH157, GH158	Mixed-Linkage glucans Backbone Cleavage (Hemicellulose)
-CAZy	CAZy	Mixed-Linkage glucans	GH3, GH16, GH17, GH55, GH1	Mixed-Linkage glucans Oligo Cleavage (Hemicellulose)
-CAZy	CAZy	Xylans	GH10, GH26, GH8, GH5, GH11, GH30, GH98, GH141	Xylan Backbone Cleavage (Hemicellulose)
-CAZy	CAZy	Xylans	GH39, GH3, GH31, GH52, GH120, GH115, GH67	Xylan Oligo Cleavage (Hemicellulose)
-CAZy	CAZy	Beta-mannan	GH113, GH134, GH26, GH5	Beta-mannan Backbone Cleavage (Hemicellulose)
-CAZy	CAZy	Beta-mannan	GH26,GH130, GH113, CE2, CE17, GH2	Beta-mannan Oligo Cleavage (Hemicellulose)
-CAZy	CAZy	Alpha-mannan	GH99, GH76	Alpha-mannan Backbone Cleavage (Hemicellulose)
-CAZy	CAZy	Alpha-mannan	GH76, GH92, GH38, GH63, GH47, GH125, GH130	Alpha-mannan Oligo Cleavage (Hemicellulose)
-CAZy	CAZy	Arabinan	GH43, GH49	Arabinan Backbone Cleavage
-CAZy	CAZy	Arabinan	GH93, GH43, GH51, GH3, GH54, GH62	Arabinan Oligo Cleavage
-CAZy	CAZy	Rhamnose cleavage	GH78, GH106, GH145, PL24, PL25, PL27, PL28, GH28	Rhamnose Oligo cleavage
-CAZy	CAZy	Fucose Cleavage	GH107, GH139, GH141, GH151, GH29, GH95	Fucose Oligo Cleavage
-CAZy	CAZy	Arabinose cleavage	GH121, GH127, GH137, GH142, GH146, GH54, GH62, GH2	Arabinose Oligo cleavage
-Nitrogen metabolism	Nitrification	ammonia => nitrite	EC:1.14.99.39	ammonia monooxygenase [EC:1.14.99.39] [RN:R00148]
-Nitrogen metabolism	Nitrification	Bacterial/Archaeal ammonia oxidation	K10944, K10945, K10946	amoA; Methane/ammonia monooxygenase subunit A (aka: particulate ammonia monooxygenase) [EC:1.14.99.39] [RN:R00148]	amoA
+CAZy	CAZy	Polyphenolics	"K05909, AA1, AA2, K00422"	Polyphenolics Cleavage	
+CAZy	CAZy	Crystalline Cellulose	"GH7, GH48, AA10, AA15, AA16, AA9, AA10, AA11, AA13"	Crystalline Cellulose Backbone Cleavage	
+CAZy	CAZy	Amorphous Cellulose	"GH5, GH6, GH7, GH8, GH9, GH10, GH124, GH12, GH44, GH45"	Amorphous Cellulose Backbone Cleavage	
+CAZy	CAZy	Amorphous Cellulose	"GH94, GH1, GH2, GH3, GH5, GH9, GH16, GH116"	Amorphous Cellulose Oligo Cleavage	
+CAZy	CAZy	Mucin	GH101	Mucin Backbone Cleavage	
+CAZy	CAZy	Mucin	"GH27, GH129, GH112, GH109, GH31, GH36"	Mucin Oligo Cleavage	
+CAZy	CAZy	Sulf-Polysachharides	"GH111, GH16, GH82, GH150, GH79, PL29, PL30, PL33, PL8, PL12, PL13, PL15, PL21, PL6, PL37, GH56, GH86"	Sulf-Polysachharides Backbone Cleavage	
+CAZy	CAZy	Sulf-Polysachharides	"PL21, PL37, PL23, PL24, PL25, GH88, PL15, PL6, GH117"	Sulf-Polysachharides Oligo Cleavage	
+CAZy	CAZy	Xyloglucan	"GH5, GH9, GH12, GH16, GH44, GH45, GH48, GH74, AA9"	Xyloglucan Backbone Cleavage (Hemicellulose)	
+CAZy	CAZy	Xyloglucan	"GH31, GH43, GH10, GH2"	Xyloglucan Oligo Cleavage (Hemicellulose)	
+CAZy	CAZy	Starch	"AA13, GH13, GH14, GH57, GH119, GH126"	Starch Backbone Cleavage	
+CAZy	CAZy	Starch	"GH133, GH15, GH97"	Starch Oligo Cleavage	
+CAZy	CAZy	Chitin	"GH18, GH19, GH23, GH73"	Chitin Backbone Cleavage	
+CAZy	CAZy	Chitin	"GH20, GH3, GH5, GH84, GH116, AA10, AA11, AA15, CE4"	Chitin Oligo Cleavage	
+CAZy	CAZy	Pectin	"GH28, PL1, PL2, PL9, PL10, PL11, PL22, PL26, PL3, PL4"	Pectin Backbone Cleavage	
+CAZy	CAZy	Pectin	"GH78, GH106, GH138, GH139, GH143, CE8, GH105, GH4, CE12, GH2"	Pectin Oligo Cleavage	
+CAZy	CAZy	Alpha-galactans	GH166	Alpha-galactans Backbone Cleavage	
+CAZy	CAZy	Alpha-galactans	"GH27, GH110, GH4, GH31, GH36, GH97"	Alpha-galactans Oligo Cleavage	
+CAZy	CAZy	Beta-galactan (pectic galactan)	GH53	Beta-galactan (pectic galactan) Backbone Cleavage	
+CAZy	CAZy	Beta-galactan (pectic galactan)	"GH2, GH35, GH42, GH1, GH59, GH147, GH165"	Beta-galactan (pectic galactan) Oligo Cleavage	
+CAZy	CAZy	Mixed-Linkage glucans	"GH16, GH30, GH17, GH7, GH8, GH9, GH5, GH55, GH64, GH81, GH128, GH152, GH157, GH158"	Mixed-Linkage glucans Backbone Cleavage (Hemicellulose)	
+CAZy	CAZy	Mixed-Linkage glucans	"GH3, GH16, GH17, GH55, GH1"	Mixed-Linkage glucans Oligo Cleavage (Hemicellulose)	
+CAZy	CAZy	Xylans	"GH10, GH26, GH8, GH5, GH11, GH30, GH98, GH141"	Xylan Backbone Cleavage (Hemicellulose)	
+CAZy	CAZy	Xylans	"GH39, GH3, GH31, GH52, GH120, GH115, GH67"	Xylan Oligo Cleavage (Hemicellulose)	
+CAZy	CAZy	Beta-mannan	"GH113, GH134, GH26, GH5"	Beta-mannan Backbone Cleavage (Hemicellulose)	
+CAZy	CAZy	Beta-mannan	"GH26,GH130, GH113, CE2, CE17, GH2"	Beta-mannan Oligo Cleavage (Hemicellulose)	
+CAZy	CAZy	Alpha-mannan	"GH99, GH76"	Alpha-mannan Backbone Cleavage (Hemicellulose)	
+CAZy	CAZy	Alpha-mannan	"GH76, GH92, GH38, GH63, GH47, GH125, GH130"	Alpha-mannan Oligo Cleavage (Hemicellulose)	
+CAZy	CAZy	Arabinan	"GH43, GH49"	Arabinan Backbone Cleavage	
+CAZy	CAZy	Arabinan	"GH93, GH43, GH51, GH3, GH54, GH62"	Arabinan Oligo Cleavage	
+CAZy	CAZy	Rhamnose cleavage	"GH78, GH106, GH145, PL24, PL25, PL27, PL28, GH28"	Rhamnose Oligo cleavage	
+CAZy	CAZy	Fucose Cleavage	"GH107, GH139, GH141, GH151, GH29, GH95"	Fucose Oligo Cleavage	
+CAZy	CAZy	Arabinose cleavage	"GH121, GH127, GH137, GH142, GH146, GH54, GH62, GH2"	Arabinose Oligo cleavage	
+Nitrogen metabolism	Nitrification	ammonia => nitrite	EC:1.14.99.39	ammonia monooxygenase [EC:1.14.99.39] [RN:R00148]	
+Nitrogen metabolism	Nitrification	Bacterial/Archaeal ammonia oxidation	"K10944, K10945, K10946"	amoA; Methane/ammonia monooxygenase subunit A (aka: particulate ammonia monooxygenase) [EC:1.14.99.39] [RN:R00148]	amoA
 Nitrogen metabolism	Nitrification	Bacterial (aerobic-specific) ammonia oxidation	K10535	hao: Hydroxylamine dehydrogenase [EC:1.7.2.6] [RN:R10164]	hao
-Nitrogen metabolism	Nitrification	Bacterial (anaerobic-specific) ammonia oxidation	K20932, K20933, K20934, K20935	hzs; Hydrazine synthase subunit (aka: hzsC) [EC:1.7.2.7] [RN:R09799]	hzs
-Nitrogen metabolism	Nitrification	nitrite => nitrate	K00370, K00371	nxrA; Nitrite oxidoreductase, alpha subunit [EC:1.7.99.-] [RN:R00978]; nxrB; Nitrite oxidoreductase, beta subunit [EC:1.7.99.-] [RN:R00978]
-Nitrogen metabolism	Denitrification	nitrate => nitrite	K02567, K00370, K00371, K02568	periplasmic nitrate reductase NapA [EC:1.7.99.-] [RN:R00798] or nitrate reductase 1 NarG [EC:1.7.99.-] [RN:R00798]
-Nitrogen metabolism	Denitrification	nitrite => nitric oxide	K00362, K00368, K15864	respiratory nitrite reductase [EC:1.7.1.15] [RN:R00787]
-Nitrogen metabolism	Denitrification	Dissimilatory nitrite reduction to ammonia (DNRA)	K03385, K15876	nrfA; Nitrite reductase (cytochrome c-552) [EC:1.7.2.2] [RN:R05712]; nrfH; cytochrome c nitrite reductase small subunit [EC:1.7.2.2] [RN:R05712]	nrfA
-Nitrogen metabolism	Denitrification	nitric oxide => nitrous oxide	K04561, K15877	nitric oxide reductase [EC:1.7.2.5] [RN:R00294]
-Nitrogen metabolism	Denitrification	nitrous oxide => nitrogen	K00376	nitrous-oxide reductase [EC:1.7.2.4] [RN:R02804]
-Nitrogen metabolism	Nitrogen fixation	nitrogen => ammonia	K02588, K02586	nitrogenase iron protein [RN:R05185]
+Nitrogen metabolism	Nitrification	Bacterial (anaerobic-specific) ammonia oxidation	"K20932, K20933, K20934, K20935"	hzs; Hydrazine synthase subunit (aka: hzsC) [EC:1.7.2.7] [RN:R09799]	hzs
+Nitrogen metabolism	Nitrification	nitrite=> nitrate	"K00370, K00371"	"nxrA; Nitrite oxidoreductase, alpha subunit [EC:1.7.99.-] [RN:R00978]; nxrB; Nitrite oxidoreductase, beta subunit [EC:1.7.99.-] [RN:R00978]"	
+Nitrogen metabolism	Denitrification	nitrate => nitrite	"K02567, K00370, K00371, K02568"	periplasmic nitrate reductase NapA [EC:1.7.99.-] [RN:R00798] or nitrate reductase 1 NarG [EC:1.7.99.-] [RN:R00798]	
+Nitrogen metabolism	Denitrification	nitrite => nitric oxide	"K00362, K00368, K15864"	respiratory nitrite reductase [EC:1.7.1.15] [RN:R00787]	
+Nitrogen metabolism	Denitrification	Dissimilatory nitrite reduction to ammonia (DNRA)	"K03385, K15876"	nrfA; Nitrite reductase (cytochrome c-552) [EC:1.7.2.2] [RN:R05712]; nrfH; cytochrome c nitrite reductase small subunit [EC:1.7.2.2] [RN:R05712]	nrfA
+Nitrogen metabolism	Denitrification	nitric oxide => nitrous oxide	"K04561, K15877"	nitric oxide reductase [EC:1.7.2.5] [RN:R00294]	
+Nitrogen metabolism	Denitrification	nitrous oxide => nitrogen	K00376	nitrous-oxide reductase [EC:1.7.2.4] [RN:R02804]	
+Nitrogen metabolism	Nitrogen fixation	nitrogen => ammonia	"K02588, K02586"	nitrogenase iron protein [RN:R05185]	
 Nitrogen metabolism	Nitrogen fixation	Nitrogen fixation altennative	K22896	vnfD; Vanadium-dependent nitrogenase alpha chain [EC:1.18.6.2] [RN:R12084]	vnfH
-Sulfur metabolism	Sulfur metabolism	dissimilatory sulfate reduction (and oxidation) sulfate => sulfide	K11180, K11181	dissimilatory sulfite reductase alpha subunit [EC:1.8.99.5]	dsrA or dsrB
-Sulfur metabolism	Sulfur metabolism	thiosulfate => sulfite	K08352	thiosulfate reductase / polysulfide reductase chain A [EC:1.8.5.5]	phsA, psrA
-Sulfur metabolism	Sulfur metabolism	Thiosulfate oxidation by SOX complex, thiosulfate => sulfate	K17222, K17223, K17224, K17225, K22622, K17226, K17227
+Sulfur metabolism	Sulfur metabolism	dissimilatory sulfate reduction (and oxidation) sulfate => sulfide	"K11180, K11181"	dissimilatory sulfite reductase alpha subunit [EC:1.8.99.5]	dsrA or dsrB
+Sulfur metabolism	Sulfur metabolism	thiosulfate => sulfite	K08352	thiosulfate reductase / polysulfide reductase chain A [EC:1.8.5.5]	"phsA, psrA"
+Sulfur metabolism	Sulfur metabolism	"Thiosulfate oxidation by SOX complex, thiosulfate => sulfate"	"K17222, K17223, K17224, K17225, K22622, K17226, K17227"		
 Sulfur metabolism	Sulfur metabolism	tetrathionate => thiosulfate	K08357		ttrA
-Other Reductases	Reductases and Electron transport chain components	selenate/Chlorate reduction	K17050	selenate/chlorate reductase subunit alpha
-Other Reductases	Reductases and Electron transport chain components	TMAO reductase	K07811	trimethylamine-N-oxide reductase (cytochrome c) [EC:1.7.2.3]
-Other Reductases	Reductases and Electron transport chain components	mercury reduction	EC:1.16.1.1	mercury(II) reductase
-Other Reductases	Reductases and Electron transport chain components	arsenate reduction, pt 1	EC:1.20.4.1	arsenate reductase (glutaredoxin); ArsC (ambiguous)
-Other Reductases	Reductases and Electron transport chain components	arsenate reduction, pt 2	EC:1.20.99.1	arsenate reductase (donor); arsenate:(acceptor) oxidoreductase
-Photosynthesis	Photosynthesis	Photosystem I	K02689, K02690, K02691, K02692, K02693, K02694	psaA-F; photosystem I P700 chlorophyll a apoprotein A1
-Photosynthesis	Photosynthesis	Photosystem II	K02703, K02706	psbA, psbD photosystem II reaction center D1 protein [EC:1.10.3.9]	fhs (formyltetrahydrofolate (THF) synthetase)
-Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	Key functional gene 	K00399, K00401, K00402	methyl-coenzyme M reductase [EC:2.8.4.1] [RN:R04541]	mcrA
-Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	acetate => methane, pt 1	K01895	acetyl-CoA synthetase [EC:6.2.1.1] [RN:R00235]
-Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	acetate => methane, pt 2	K00925	acetate kinase [EC:2.7.2.1] [RN:R00315]	ack
-Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	acetate => methane, pt 3	K00625	phosphate acetyltransferase [EC:2.3.1.8] [RN:R00230]
+Other Reductases	Reductases and Electron transport chain components	selenate/Chlorate reduction	K17050	selenate/chlorate reductase subunit alpha	
+Other Reductases	Reductases and Electron transport chain components	TMAO reductase	K07811	trimethylamine-N-oxide reductase (cytochrome c) [EC:1.7.2.3]	
+Other Reductases	Reductases and Electron transport chain components	mercury reduction	EC:1.16.1.1	mercury(II) reductase	
+Other Reductases	Reductases and Electron transport chain components	"arsenate reduction, pt 1"	EC:1.20.4.1	arsenate reductase (glutaredoxin); ArsC (ambiguous)	
+Other Reductases	Reductases and Electron transport chain components	"arsenate reduction, pt 2"	EC:1.20.99.1	arsenate reductase (donor); arsenate:(acceptor) oxidoreductase	
+Photosynthesis	Photosynthesis	Photosystem I	"K02689, K02690, K02691, K02692, K02693, K02694, K08940, K08941, K08942, K08943"	psaA-F; photosystem I P700 chlorophyll a apoprotein A1	
+Photosynthesis	Photosynthesis	Photosystem II	"K02703, K02704, K02705, K02706, K02707, K02708, K08928, K08929"	"psbA, psbD photosystem II reaction center D1 protein [EC:1.10.3.9]"	fhs (formyltetrahydrofolate (THF) synthetase)
+Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	Key functional gene 	"K00399, K00401, K00402"	methyl-coenzyme M reductase [EC:2.8.4.1] [RN:R04541]	mcrA
+Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	"acetate => methane, pt 1"	K01895	acetyl-CoA synthetase [EC:6.2.1.1] [RN:R00235]	
+Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	"acetate => methane, pt 2"	K00925	acetate kinase [EC:2.7.2.1] [RN:R00315]	ack
+Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	"acetate => methane, pt 3"	K00625	phosphate acetyltransferase [EC:2.3.1.8] [RN:R00230]	
 Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	methanol => methane	K04480	mtaB; 5-hydroxybenzimidazolylcobamide Co-methyltransferase	mtaB
 Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	trimethylamine => dimethylamine	K14083	mttB; trimethylamine corrinoid protein Co-methyltransferase	mttB
 Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	dimethylamine => monomethylamine	K16178	mtbB; dimethylamine corrinoid protein Co-methyltransferase	mtbB
 Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	monomethylamine => ammonia	K16176	mtmB; methylamine corrinoid protein Co-methyltransferase	mtmB
-Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	putative but not defining CO2 => methane	K00200	formylmethanofuran dehydrogenase [EC:1.2.99.5] [RN:R03015]
-Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	methane => methanol, with oxygen (pmo)	K10944, K10945, K10946	pmoA; Methane/ammonia monooxygenase subunit A (aka: Particulate methane monoxygenase, or subunit Beta) [EC:1.14.18.3] [RN:R09518]	pmoA
-Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	methane => methanol, with oxygen (mmo)	K16157, K16158, K16159, K16160, K16161, K16162	mmoX; Methane monooxygenase component A alpha chain (aka: Soluble methane monooxygenase, or methane hydroxylase) [EC1.14.13.25] [RN:R01142]
-SCFA and alcohol conversions	SCFA and alcohol conversions	pyruvate => acetyl CoA v1	K00163	pyruvate dehydrogenase E1 component [EC:1.2.4.1]
-SCFA and alcohol conversions	SCFA and alcohol conversions	pyruvate => acetyl CoA v2	K00174	2-oxoglutarate/2-oxoacid ferredoxin oxidoreductase subunit alpha [EC:1.2.7.3, 1.2.7.11]
-SCFA and alcohol conversions	SCFA and alcohol conversions	pyruvate => acetylCoA f+ formate v3	K00656	formate C-acetyltransferase [EC:2.3.1.54]
-SCFA and alcohol conversions	SCFA and alcohol conversions	acetate, pt 1	K00625	phosphate acetyltransferase [EC:2.3.1.8] [RN:R00230]
-SCFA and alcohol conversions	SCFA and alcohol conversions	acetate, pt 2	K00925, K01905	acetate kinase [EC:2.7.2.1] [RN:R00315], 6.2.1.13, acetate---CoA ligase (ADP-forming) subunit alpha
-SCFA and alcohol conversions	SCFA and alcohol conversions	acetate, pt 3	K01067	acetyl-CoA hydrolase [EC:3.1.2.1]
-SCFA and alcohol conversions	SCFA and alcohol conversions	lactate L	K00016, K00101	L-lactate dehydrogenase [EC:1.1.1.27]; L-lactate dehydrogenase (cytochrome) [EC:1.1.2.3]
-SCFA and alcohol conversions	SCFA and alcohol conversions	lactate D	K03778, K03777	D-lactate dehydrogenase [EC:1.1.1.28]; D-lactate dehydrogenase (quinone) [EC:1.1.5.12], D-lactate dehydrogenase (cytochrome) [EC:1.1.2.4], D-lactate dehydrogenase (cytochrome c-553)
-SCFA and alcohol conversions	SCFA and alcohol conversions	Butyrate, pt 1	K00634	phosphate butyryltransferase [EC:2.3.1.19]
-SCFA and alcohol conversions	SCFA and alcohol conversions	Butyrate, pt 2	K00929, K01896	butyrate kinase [EC:2.7.2.7], medium-chain acyl-CoA synthetase [EC:6.2.1.2]
-SCFA and alcohol conversions	SCFA and alcohol conversions	Propionate, pt 1	K19697	propionate kinase [EC:2.7.2.15]
-SCFA and alcohol conversions	SCFA and alcohol conversions	Propionate, pt 2	K01026	propionate CoA-transferase [EC:2.8.3.1]
-SCFA and alcohol conversions	SCFA and alcohol conversions	Alcohol production 	K00001, K00121, K04072, K13951, K13952, K13953, K13954, K13980, K18857	alcohol dehydrogenase [EC:1.1.1.1]
+Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	putative but not defining CO2 => methane	K00200	formylmethanofuran dehydrogenase [EC:1.2.99.5] [RN:R03015]	
+Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	"methane => methanol, with oxygen (pmo)"	"K10944, K10945, K10946"	"pmoA; Methane/ammonia monooxygenase subunit A (aka: Particulate methane monoxygenase, or subunit Beta) [EC:1.14.18.3] [RN:R09518]"	pmoA
+Methanogenesis and methanotrophy	Methanogenesis and methanotrophy	"methane => methanol, with oxygen (mmo)"	"K16157, K16158, K16159, K16160, K16161, K16162"	"mmoX; Methane monooxygenase component A alpha chain (aka: Soluble methane monooxygenase, or methane hydroxylase) [EC1.14.13.25] [RN:R01142]"	
+SCFA and alcohol conversions	SCFA and alcohol conversions	pyruvate => acetyl CoA v1	K00163	pyruvate dehydrogenase E1 component [EC:1.2.4.1]	
+SCFA and alcohol conversions	SCFA and alcohol conversions	pyruvate => acetyl CoA v2	K00174	"2-oxoglutarate/2-oxoacid ferredoxin oxidoreductase subunit alpha [EC:1.2.7.3, 1.2.7.11]"	
+SCFA and alcohol conversions	SCFA and alcohol conversions	pyruvate => acetylCoA f+ formate v3	K00656	formate C-acetyltransferase [EC:2.3.1.54]	
+SCFA and alcohol conversions	SCFA and alcohol conversions	"acetate, pt 1"	"K00625,K00925"	"phosphate acetyltransferase [EC:2.3.1.8] [RN:R00230], acetate kinase [EC:2.7.2.1] [RN:R00315]"	
+SCFA and alcohol conversions	SCFA and alcohol conversions	"acetate, pt 2"	K01905	acetate---CoA ligase (ADP-forming) subunit alpha	
+SCFA and alcohol conversions	SCFA and alcohol conversions	"acetate, pt 3"	K01067	acetyl-CoA hydrolase [EC:3.1.2.1]	
+SCFA and alcohol conversions	SCFA and alcohol conversions	lactate L	"K00016, K00101"	L-lactate dehydrogenase [EC:1.1.1.27]; L-lactate dehydrogenase (cytochrome) [EC:1.1.2.3]	
+SCFA and alcohol conversions	SCFA and alcohol conversions	lactate D	"K03778, K03777"	"D-lactate dehydrogenase [EC:1.1.1.28]; D-lactate dehydrogenase (quinone) [EC:1.1.5.12], D-lactate dehydrogenase (cytochrome) [EC:1.1.2.4], D-lactate dehydrogenase (cytochrome c-553)"	
+SCFA and alcohol conversions	SCFA and alcohol conversions	"Butyrate, pt 1"	K00634	phosphate butyryltransferase [EC:2.3.1.19]	
+SCFA and alcohol conversions	SCFA and alcohol conversions	"Butyrate, pt 2"	"K00929, K01896"	"butyrate kinase [EC:2.7.2.7], medium-chain acyl-CoA synthetase [EC:6.2.1.2]"	
+SCFA and alcohol conversions	SCFA and alcohol conversions	"Propionate, pt 1"	K19697	propionate kinase [EC:2.7.2.15]	
+SCFA and alcohol conversions	SCFA and alcohol conversions	"Propionate, pt 2"	K01026	propionate CoA-transferase [EC:2.8.3.1]	
+SCFA and alcohol conversions	SCFA and alcohol conversions	Alcohol production 	"K00001, K00121, K04072, K13951, K13952, K13953, K13954, K13980, K18857"	alcohol dehydrogenase [EC:1.1.1.1]	 
diff --git a/data/methylotrophy/methylotrophy.faa b/data/methylotrophy/methylotrophy.faa
new file mode 100644
index 00000000..00a27d8e
--- /dev/null
+++ b/data/methylotrophy/methylotrophy.faa
@@ -0,0 +1,102 @@
+>METHYL_0034 MtvA_vanillate/O-demethylse_specific_methylcorrinoid:THF_methyltransferase uncultured_Treponema
+METPLCIDSSNPRTIVEVFGFAQKPGLINSVSLEGDKTDLIFPLIAATEWSCIALLCDNDGIPRTVEKRLAIARLIIDRAKAAGISPGRLHIDPLVMALSAEGSSMTTFLKCASAIKQWEPDIHITSGLSNISYSLPQRKSINQAFLTLAMGSGMDSAIMDPLNKGMMAAMYATEALLEKDKLCLKYIRAYKKGLIQI
+>METHYL_0033 MtvC_vanilate_corrinoid/methoxy_corrinoid_Syntrophaceticus_schinkii_A0A0B7MDG8-1
+MANLIDELKNAIVELEADKVVSSVKAGLDEGLNPLSLVKSLQAGMVEIGDRFAKGEYYLSELIMSGEIMKNAMALIEPKLAGLDQEHKGSIVIGTVQGDIHDLGKNIVVMLLKGAGYNVVDLGVDVPAEKFIEATKEHKAPLVAMSVLLTGCQDPMKDTIKAIRDAGLNDVKVLIGGNYVDEKVKEYCGADYFGTSADEGVKVANQIFA
+>METHYL_0033 MtvC_Moorella_thermoacetica_Q2RLG8
+MLTDTLSKAMAELEEEQVLAQVKERLGGGVAPLEIVKTLQEGMVEVGNRFQSGEYFLSELIMAGEIMKGAMDILEPHLGGESGEHKGTIVIGTVKGDIHDLGKNIVIMLLKGAGYKVVDLGVDVPKERFVEALQETKAPLVGMSVLLTSCQEAMKETIEAIRGAGLDTRVVIGGNYIDETVKNYVGADYYATTATDGVKVAAEVFGA
+>METHYL_0044 MtoA_or_mtrH_AF_0009_Archaeoglobus_fulgidus_DSM_4304_WP_010877523.1
+MFRFENQKVFEIGGVKIGGEVGENPTVLIGSIFYGKHKIVEDEKRGIFDREGAEALIREMEDLSDKTGNPGLLDVVGMSEEAMIKYIDFVADVTDSPFLIDSAIADIKLAGVKHADEVGLSDRVIYNSISPESKDAEIEALANSKVEAAVVLAYTYNVISSAARLQALEKAMAKVEKAGITKPIVDTFVMDVPSLPAAAKAAIDIKRKYGLPTGSGAHNAIGSWKGFKNMFGKEAEKAATIVAVTMQIILGSDFVLYGPIEDCREVFPAMYTIDTAYKYFRRTKDWIEMV
+>METHYL_0044 MtoA_methoxy_specific_methylcorrinoid:H4MPT_methyltranferase_(AF_0009) _Archaeoglobus_fulgidus_DSM_4304_ AAB91219.1
+MVLMFRFENQKVFEIGGVKIGGEVGENPTVLIGSIFYGKHKIVEDEKRGIFDREGAEALIREMEDLSDKTGNPGLLDVVGMSEEAMIKYIDFVADVTDSPFLIDSAIADIKLAGVKHADEVGLSDRVIYNSISPESKDAEIEALANSKVEAAVVLAYTYNVISSAARLQALEKAMAKVEKAGITKPIVDTFVMDVPSLPAAAKAAIDIKRKYGLPTGSGAHNAIGSWKGFKNMFGKEAEKAATIVAVTMQIILGSDFVLYGPIEDCREVFPAMYTIDTAYKYFRRTKDWIEMV
+>METHYL_0043 MtoC_AF_0006_Archaeoglobus_fulgidus_DSM_4304_AAB91221.1
+MADVRKEFVQALADLDEAKTVELTKKRVESGEDPFTILEDVRKATDIIGKRFEEGRYFVSDLIMAGEILKQVMEILRPLLGEKKAESKGKVVIGTVEGDVHDIGKNIVIALLEAEGFEVVDIGVDQPPEAFVEAANQHNPDVVGLSGLLTEAIESMKRTVEALRKAGYKGKIIIGGGRTSEEAKEYTGADDWADDAAVGVRKIKALVGVE
+>METHYL_0043 MtoC_Archaeoglobus_fulgidus_DSM_4304_methoxy_compounds_including_2-methoxyphenol_AAB91218.1_NCBI_mtac2
+MSNLFYIKSFIFLSQLTLIESFFIFSKLHGGDTLEEFVQALADLDEAKTVDLTKKRVDSGEDPFTILEDVRKATDIIGKRFEEGRYFVSDLIMAGEILKQVMEILRPLLGEKKAESKGKVVIGSVEGDVHDIGKNIVIALLEAEGFEVVDIGVDQPPEAFVEAANQHNPDVVGLSGLLTEAIESMKRTVEALRKAGYKGKIIIGGGRTSEEAKEYTGADDWADDAAVGVRKIKALVGVE
+>METHYL_0045 O-demethylase_D._hafniense_DCB2_corrinoid_dep_MT_Dhaf_4610_including_vanillate_isovanillate_syringate_guaiacol_methylchloride
+MLTIKQNLLETIRGGNPDRFVNQYEFMDIILENPVDFMAPPGGSIKTGWGITFRWPEGQIGQFPVHDEEHKVLKDITKWREQVKAPEIPDTDEAWAAAVEHANSIDRNEKYVTAFVAPGVFEMCHHLMSMEDALMALYEEPELMHELIDYLTEYELKLAEIICRRLKPDALFHHDDWGSQKSSFISPAMFEEFYLPAYKKIYSFYKQNGVELIVHHSDCYAANLVPFMIEMGIDIWQGVMTTNNTPELIKQYGGKISFMGDIDSGVVDFPTWTREIAAREAERACTNCGKHYFIPCLTQGLGFSSFPGVYDCVSEEIDKLSKKMF
+>METHYL_0046 O-demethylase_D._hafniense_DCB2_corrinoid_Dhaf_4611_including_vanillate_isovanillate_syringate_guaiacol_methylchloride
+MSKIAEVKAMVEAGKAKLVPGLVQEALDAGNAAGDILAGMIDSMGVVGDKFSAGELFVPEMLMAAKAMSKGVDVLKPHLTGESATSLGTCVIGTVAGDLHDIGKNLVAMMLESVGFNVVDLGVDVSAEKFVDAVRENDNVKIVACSGLLTTTMPAMKETVQSLKNSGLTGFKVIVGGAPVSQAMADEIGADGFAPDAGGAAVKAKELAHA
+>METHYL_0047 O-demethylase_D._hafniense_DCB2,_methylcorrinoid:THF_methyltransferase,_Dhaf_4612
+MILIGEKINGAIPSVAKAIAAKDADFIRNLAKVQSEAGVNFLDVCASVDNDIELETLKWLIDLVQEVSDIPIAIDSPNANVIAEAIKFCNKPGLINSVSMEGDKVEVIFPIIADTKWECVALLCDDTGIPQDTEKRLEVFGTLMAKAKQYNIAPSRLHIDPLVQMLCTSEDGILAIMEVIKEIKAQYPKIHITGGASNISFNLPIRRLVNQAFIVLAMGAGMDSAIVDPTKQDLMGMIFATEALLGQDEYCMEYIGAYREGKFGQK
+>METHYL_0039 SECO_secoisolariciresinol_corrinoid_methyltransferase,_E._limosum_ZL-II,_ELI_2003
+MAKKFDKLAINNLDDFIYGSCPNPVTTKSGMVIGGGTIYPEINFTLPGMDVNDATIDKALGIYSNIIDGVLKRAAELYAPGVLVEFETVPDFTEHPKYGIDANRILINGIKEAADKYGLKASLRTTPNDLREMSRPPVMRGGKYWDTMLELYEQCAKDGSDFLSIESTGGKEINDEALVKADIRKAIFAMGVLGCRDMEYLWGNLVKLSDENGCFAAGDSACGFANTAMVLAEKGFIPHVFAAVMRVVAVPRALVAFEQGAVGPSKDCAYEGPYLKAITGSPIAMEGKSAAGAHLSPIGNIAAAVADTWSNESIQQVKLLSEMAPVVGMEQLVYDCRLMNVAKEKGQGLIMRDLLTESDAPLDVQAWVLRPDVVLKIAGELVKEQDNFLRTKLAAKLTINELRDAIKAEKVKADRRDMKWLDKMEKAVDTIPDDPEQFYAEIKPELDMDKWHPEGYGLKA
+>METHYL_0040 SECO_secoisolariciresinol_corrinoid_E._limosum_ZL-II,_ELI_2004
+MAILEDIQNCVLDGELDEIKDLVQKAVDEGIDPATIINDGLIGGMNIVAPLFKSGEMFVPEVMESADTMNEGMQVVKPLITDADMLTKGKVIIGTVNGDLHDIGKNLVVLMMESRGYTVVDLGVDVKEDQFVQAIKEHKPDIVGMSSLLTTTMMKIDDTIKVINDAGVRGDVRIIIGGAPISQEFADDVGADGYSEDASTAVELCDRMMAM
+>METHYL_0041 SECO_(secoisolariciresinol)_methylcorrinoid:THF,_E._limosum_ZL-II,_ELI_2005
+MLTIVGELINTSRPAVKEAVNNKDEAFIRELARKQADAGATYIDVNCGNMVKNELEIMEWLVNIVQDEVDTPLCIDSPNARALDVGLALCKNGRPMINSISDEDERYESVLPLIKKYNAKIVVLCMDSTGMPETSADRMKVVKNLHAKLKAEGIADDDMYFDPLVKPISSVTSAGEEVLDTIRQIRQDYPDVHFMCGLSNISYGLPNRSILNRLFVVQTMTLGMDGYVLDPTNGKMMADIITATALLGKDNYCSKYIKAHRKGKLDASPDA
+>METHYL_0035 OdmA_vanillate_corrinoid_Acetobacterium_dehalogenans_O87603-1
+MSKIEEVKAKVEVGKSKLVPGLVQEALDEGSAPGEILQAMVDSMGVVGEKFSSGEIFVPEMLIAAKAMSKGVEVLKPLMAGDGSASLGTCVIGTVAGDLHDIGKNLVSMMIESAGFDMVDLGVDVPADTFVQAVKDNTNVKLVACSGLLTTTMPALKEAVQTIKAAYPDMKVIVGGAPVTPEYAAEVGADGYAPDAGSAAVKARELATA
+>METHYL_0037 Vdma_veratrole_corrinoid_Acetobacterium_dehalogenans_Q6W002-1
+MSKITEVKQLVEAGKSKKIGPAVQEALNAGGQPVEILQPMVDSMSVVGDKFSAGEIFVPEMLIAAKAMSKGVDVLRPLMAGDNAASLGTCVIGTVAGDLHDIGKNLVSMMIESAGFTMVDLGVDVPAEKFVAAARENDNVTLIACSGLLTTTMPALKEAVATIKASGLAGCKVIVGGAPVTSEFAAEIGADGYAADAGSAAVKAKDLVK
+>METHYL_0036 VdmB_veratrole_corrinoid_methyltransferase_Acetobacterium_dehalogenans_Q6W001-1
+MNQRENFFAMIEGKKPEFIPNSMEVYKTCVMATSIIDSPFQGGLDAYGVNWIATKEGSIPEPNKFMFNDITDWKDHVKFPNVDTLGIEEAAKMELADVKRDEMVINVFSACGLFERMAAFMGFENTLCSLVEDPDASREFFEAFADFRIDCHNRIIDAYQPDVITYFDDLATANGLFMSPKVYREVIKPAHQRIAEAVTSRGVIFSQHTCGKCEEIVGDFVEMGAKIWHSAQISNDLEGIMDRYKGKLIIEGGWDSSGPVSYIGASIEDLIEEAKRCVRVYGPKGNYIFMPVLMNENGNSLLVGDPRLEPMLKAFNEINKL
+>METHYL_0038 VdmD_veratrole_specific_methylcorrinoid:THF_methyltransferase_Acetobacterium_dehalogenans_Q6W003
+MIIIGEKINGAIPATAKAIAARDAEYIKHLARIQTAAGVDYIDVCASVENNVELETMKWLIDIVQEVTETPIAVDSPNEQTCIAAMSYCNKPGLFNSVSMEGNKVDVGFAAIADTSWECVALLNSDKGIPKTATDRLDVFTDIMAKAKAFGIDPSRLHIDPLVEMLCTSEEGIAVVTEVIREIKNQYPTIHVTGAISNISFNLPARKTVNMGFTVMAMMAGLDSAILDPTDRDLMGIIFATEALMGEDEYCVEYIRAYRQGIHGAVKK
+>METHYL_0026 MtsB_corrinoid_protein_Methanosarcina_barkeri_Q48925-1
+MIRHIDLAVQNILEMKEKEPAKFKRLIDEGIMIGLGVDLEDGNKEVTTVDQIKNQNRPKDPEYASVAEAVIEGNNAETVKLISALLEKGKDPTDLVLNALMPGIQTVCELYDIGESYVPEILLANEALMKGVELCQKKKGEVPSQGKVVSLVIVGDLHDIGKNIVAAILRANGFEVIDLGRDVTVEAAVEAVKSTKANLVTGTTLMSTTKGGLKALANALEPEGVPLACGGAAVDRRFVDTFGNSVYGRTPLDAVKIAKEICEGKSWEEARNELY
+>METHYL_0026 MtsB_Mx_luminyensis_WP_019177442.1
+MTRHLGLLAEEMLEMRTKDPERYRRLINEGMLAELGYNASNRSSKQASIDDIRNKHRPREASYAAISDAVISGKRQRVKELVEASLKQGKDPVNLVTNALMPGIQTLCELYDQGKAFVPEILMSNDAMLGGISLCQDKLGDVPRKGKVATFVAEGDLHDIGKNIVVAILRANGFEVMDLGRDVPVAKVVAAAKEHGLDMISGSTLMSTTKSGLKRTAETLEEEGIRAPIACGGAAVSKNFVETFGHAIYGRSPLDAVKIATEVCSGKDWKEVREKLR
+>METHYL_0027 MtsD_MA0859_Methanosarcina_acetivorans_C2A_Q8TSD9-1
+MLEAFFMAADILNQLAEAVVDGDDDLAEELAYKALEEGVDPYDAIVNGLARGMAIVSDQYEKGEAFVPHLLLASGAMYAGMDILSPEMIKEGEAMQAVGVIGTIEGDVHDIGKNLVKTMLSAGGFEMIDLGADVPIEKFVETAKERKADIISMSALMTTTMTNMEKVIEILQEEGIRDSMKVMIGGAPVSEEYASGIGADSTHPDAMHASAWASEAVKELEPKAARWSEEKINLGKIKYREILAKKTVSDKVDVGLETANKIKEEFESIGVKSKEEMTHIDRTISAMSDKKVDHLPVYPLACGVLRKFVPVTYKEYATNEDAFVQSAYLGSKYLDLDMFVGLIDLSATSADFGCKIKYPEDDTPSSEGHIKDYEKIEVPELKEGTRGYELVMASKKAKEKLNKELNTPFVGFHEGPLLTLTQLMGADRVLMDMKTQPDVVLEAVQKCTDYVCQLSELFFNEDACDALCIDNLWSNNVIMSEQDYWKFDGKFVYDQQIPIFKQYNQPYIIHNCADAVHFETQIRKFGTALYSYAYYEKSRDKGSQNYADLIPKYGDMCCMMGEVNPVEFMDGSAAGVQKVKDDTKNLLENVLPVLKENGLQSKYILSSGCEIPPGGPLTTVQAMVNVVKELGPELQKNIMG
+>METHYL_0028 MtsF_MA4384_Methanosarcina_acetivorans_C2A_Q8THX4
+MAKEDILNTLADAVVDGDDELAEEFAQKALDEELDAYEAIVDGLARGMKIISDMYERGEAFVPSLLLAADAMYAGMDILTPYMKVDGTAAPKNVIIGTVEGDVHDIGKNLVKTMMTAAGFNMIDLGCDVPLDKFAETAKEKKAAAISMSTLMTTTMGGMETVIEQLQEEGIRDSLIVMVGGAPISQTFADSVGADGTALDASAAVETLTSLVSELPSDSWSDSAIAASKMKYKEVLAQKSGKEKVDIGRITAEKIIAEFDSVVPKFNETMTKAERFGAAFQDKKVDRLPVAPLACGVSRKFVPCSYVDYSTKAEKYADCVEAGIKYFNMDTFVGLTDLCVDAADFGATIRYPEEDTPAATGHLEDYEKLEVPELKEGTRAYNLIQGNKLATEKAHALDAPMTALIEGPMVALTQIMGATRVLSDLRTNPDVVLKALDKTTVYVEEIMKGMFEEAQPDNLCMVNLWTNNVILSADEYMKSEGQVMQNRIAPLYKKYNKPVVIHNCADAPHWELINKWNTEYYSYTFYPDEAGKGSKDHKYLINNYGKETMFGGEVSPIVFLDNSPEGLQKMKADTIALQESVLNTLKENGMQSKYMISTGCEVPPGAPCDSITAQTYTVAEKGPELYKKIIG
+>METHYL_0029 MtsH_MA4558_Methanosarcina_acetivorans_C2A_Q8THF9-1
+MAIENENQGADAISEEELFRQMAEAVVDGDDEIIEELANRVLELNIDPYTAIVEGLTKGMSIVSDMYENGKAFVPNLMVSAGAMYEGLDILSPYLKSDSTNKPSKIIIGTVEGDVHDIGKNLVKTMMTAAGFDMIDLGSDVPLSSFVSSARDQKADAISMSTLMTTTMPGMEKVIEQLKEEGLRDSLLVMVGGAPINADYAAKIGADATRDDASAATEWLKGAIVELPDADLRWSEKQISLNKVKYKEELAKKGTVEAVDIGLETAKAIIEEFESVGVKTKESMTHADRTVSAMSDKKVDRLPVYPLACGVLRKFAPVTYKEYATNEDAFVQSAYLGSKYLDLDMFVGLIDLSITSADLGCGVKFPEEDTPSSEGHLEDYEKIEVPEVKEGTRAYELIKATKLAKAKLNSELATPMVGFHEGPLLTLTQLMGASRVLGDMNTNPDVVLKAVDKCADYVAEVSRAFFEEDACDALCIDNLWSNNVIMGQDDYWKFDGQFVYNKHVPVFKEYNQPYIIHNCADAVHYDIQISKFGTALYSYAYYPSGKGKGSYSYDELIPKYGKTCCMMGEVDPIQFLDNSPEGIQKIRNDTESNLRGAIQALKENGFQSKYVMSTGCEIPPGAPLDTSKAMVDVVKELGPELQKMIG
+>METHYL_0030 MtpA_MA_4165_methylmercaptopropionate:corrinoid_methyltransferase_Methanosarcina_acetivorans
+MVSEMTSKERVFAMLNRKPVDRVPVITGSVMVKEYIEKSGSSWPDYHSNAEMMVNTVSLMHTDAGLDNIVMPFGMFIESMALGLEVKMGRIDIQPSVRSFFNKPEEVKYDNFLEDKYVQTTLDAIKLAKEKYPDAAVTAFLVAPITLAGDLMGAENLSMLSIKCLQKEKQMQKMKDWISIALEINKIYAEACVEAGADILYYSDASASPNLVMPEFYYQVAVPAEKEIGDFVHHLGCPWELHICGDTVPIIEGMASTGADCLSVEQAVNMEEATKIAGDVPVVGNVTPLLMVEGTEAQIIEETRKGLDGGAKASMLGCGTPPLSSSDKLKTWVKAAADWSADKL
+>METHYL_0031 MtpC_MA_4164_Methanosarcina_acetivorans_C2A_Q8TII5
+MDDLPEEVQELIEELDEAAEDEDEDAIKDLTQKLLATGVDVEAITLKKLALLVMDGEEEMTQGWTQVAIQIGTDPFKTLIEGLAAGMSLIGKKYEEGEAFVPQLLIASAAMYGGMDLLAPYMKQDENSGSKAATVVIGTVEGDVHDIGKSLVKTLLSANGFNCVDLGNDVPASRFIEAARENKATAVSMSTLMTTTMAEMPKVVKMLENEGIRDKLLVMVGGAPITAEYASQIGADVSPHDAASAASWLKGAVFDFPSESVRWS
+>METHYL_0001 MtgC_DSY3155_Desulfitobacterium_hafniense_Q24SP8
+MIMSLLDELKQAIIDGDEDIVAELSQKAVDEDLDLVDTVQSGLVKGIEVVGTAWKEGEMFLPDVMMSAEAMKVGLAILEPEIAKKGMSEGESKGKIVLGTVEGDIHDIGKNITGAMFTAAGYKVIDLGTDIKAEGFVAKAQEVGADIIGASALLTTTMIKQKELIEYLKEKNLRDSYKVLVGGGPTSQVWADEIGADGWAETADDAVELANKILGK
+>METHYL_0002 MtgA_DSY3157_Desulfitobacterium_hafniense_Y51_substrate_glycine_betaine_corrinoid:THF_Q24SP6-1
+MFKFTAQQHVYDINGVKVGGQPGEYPTVLIGSIFYRGHKIVSDGQKGIFDKDAAKALLDQEAELSAETGNPFIIDVLGESVEALTKYVEFILENTTAPFLLDSISPDVRVGALKNLGKDPEIQKRLIYNSIEEHYTEEELAAIKEAGLKTAVILAFSKKALKPNARIDLLQGKDDKEGLIAAAKRAGIEQFLVDPGVLDVASNSWTTEAINVVKEQFGYPGGCAPSNAVYLWKKMRSKGTPFFEVAGAAVFTYPITQGADFILYGPMMNAPWVYRAIATTDAMIAYNNKLTGVKMGTTEHPLLKIF
+>METHYL_0003 MV8460_methanogenic_Methanolobus_vulcani_b1d_substrate_glycine_betaine_WP_154809802.1
+MIPKFDAFTNEQVESIHEHSMKILEEIGIDFLYEPALEIFKANGQRVEGNRVYLDRKFVEEQIKKAPSEFTLHARNPENNLVCGGENIIFMPGYGVSFIYEADGSRRDSFMEDYDNFVKLAGASENLHMTGGIIADPSDVPEEMKHLKMLYSSIKNSDKCFMGSASNRERAEDVIEMASILFGGRDVIKEKPAIICLINSISPLKFDDYMAGSLMAYAEAGQPVVVAALVMAGSTGPATIAGSLSVQNAEVLAGITLAQCVNPGTPVVYASSSAITDMNSGALSIGNPECALFTAACAQMGRYYGIPTRSGGGLTDSKLVDAQAGYESMMTLMTAGVTGINYVLHTAGILEGYMAMSYEKFVVDDEIAGMVLRYLKGLDFSEDAFGFDVIKKIGPGKHFLAHKHTRKYYPIELRDSELSDRRPYNDWEKEGLDTLQRAKKQWQGVLENYEAPELDADVDKALLEFMEKRFAELKK
+>METHYL_0004,METHYL_0001 MV8465_Methanolobus_vulcani_b1d_corrinoid_mtgC_homolog_WP_154809803.1
+MVTQDEINSKAKDAVMDFDDELVEEICEEAIDAGLDAVSLIQDGLTAGMIEIGNQFNEGKLHLPHVIAAAEAMSAGVAILTPVLEEQGGTTESKGKVAIGTIEGDIHTIGKDIVATMLKVDGFEVIDLGQDVAITTFVEAVKKHKPLIVGSSALMTTTMTSQAQVEEQLKEAGLRDSVLTMIGGAPVTQEWANKIGADIYAENATDAVAKCRAAAGEC
+>METHYL_0007 MtcB_L-carnitine:corrinoid_methyltransferase_Eubacterium_limosum_ATCC_8486
+MIRNSLTDVFFAKDDVENLHEGVLRVLSKVGVKIENDEALGIFEQHGARVENGTVYIGEVLLNKALQTVPANFELQGFDRTVQVGLDHDPVVIPTNGTPMVLNFDGSYSDTNTDDLVNFYKLIDTSDVMQVTSEIAVDVPGLDKTKDSLLAQTALLMKYSHKPIYNILGATIHNYKKGSVAQGVRENIQFAKKYYGYDDKYVIYSGTCVISPLGVGWEAMDHFMGFIKENQPISITACSMTNLTAPGSLYGSVVEDAAAILSIVVLSQLMNPGLPVLYTSLSSMSDMRYVQLCMGAPEFALITLGHIALANFYKIPVRVGGALGDAFKADYQAGVESFVGLMAPMLSQSAMIPHGCGTMGSFNLTSYEKFIMDEETIRYLMRLRRGFEVSDKRKEKALKDITKVGPRGNFLGGRTPKEYREDNYLASEVFNRKGCKENTREEQGDIRDRARKVYDARMEAYELPDTTLEQKKLLNTELPEQYKFDI
+>METHYL_0006 MtpB_proline_betaine:corrinoid_methyltransferase_Eubacterium_limosum_ATCC_8486
+MYVNRRFYDKYVSTRDVELLHEYSLRVLKEVGVSFDCEEALEIFKKHGATVEGSIVKIDEDLLNQALETAPKTFTITTSAGETKIGERYKPKTVGCYGPPKFLFEDDEYRVAKKDDMVKFLKLMDTSDVTDFVNNSAYDTPDLDKTKEDFYLPQVAMCLKYSQKPTYGNVANSMNVRGKSLKQEAKDIAKLYKEFYDIWDRPVLLTNTCALSPLGYSYEVLDNIMGLVEEGQPVTIITCSMTNLTAPAALLGSVIQNNATILAGIVLTQLINPGNPVIYGTVSTATDMRNVACSIGAPEAQLIQMASLALGRYYQLPVRTGIAGTDSLKPDYQAGVESFMILMTTYLGKSDFVLNHAGILQAYALGSYEKFVLDEEVNRILLRLNRGIDISDVKAEKVFDAIKKAGPLGNYLSGRTPKEYRQEHWLTKLFNRQAGNPQPIFDEIGDLRERASKEVEERVAGYTLPDLTKTQKDILNRYLPEDEKF
+>METHYL_0008 MtyB_gamma-butyrobetaine:corrinoid_methyltransferase_Eubacterium_limosum_ATCC_8486
+MLKGNLFTTFYSKDDIELIHESVLRVFNEVGVKFEYEEALELFKKHGARVEGDLVFIPEELLNKALSTIPESFEIVGPESKLEIGIGKGLVVAPTNGCPNLEDWDGNYRQTNADDLENFYKIINTSDVYGISSQVAADIPGFENCPTESALAQMAMMAKYSRKPMYNILGITPHNYKRGNAREGARECVQLIKKYMDNFDDYVCYSGMCVLPPLTVGTDALEHYFAFAEEKQPITITTCSMTNMTAPPSLMGSIVADFANMLAVAVMIQLIEPGLPVILSPFSSVSDMREVRLMTGAPEFLMIMSGHIAMGDFYRIPVRCSGALADGFTYDYQAGVESTLGALAVSLSNACILPHASGDLSNFNLLSFPKFMMDEEMLRYMKRLHDGVAISEKKANVELIKKVGPRGVYLKGRTPKDYREETYLTSPVFNRGTCNEEGRAATPPIQERAYKVYKERIESFELPDMTQAQKDLLNEHLPEKFKIK
+>METHYL_0009 MtqC_promiscuous_QA_corrinoid_Carnitine_ProlineBetaine_Butyrobetaine_Eubacterium_limosum_ATCC_8486
+MADWKNLTQAVGDLEEDDVMEILNDFVATNPTEAEAEEAVAACQAGMAVVGDLFEEGEYFVGDLIFAGELLTEAINVLKPVLGSGDTAVAGTILIGTAHGDLHDIGKNIFRSMAEAAGFQVTDLGIDVAIDTFVEKAKEIKPDIIGISGVLTLAIDSMKETSDALKAAGVDSKLIIGGNPVTKEACEYVGADDFTTNAAEGVKICQAWVG
+>METHYL_0010 MtqA_promiscuous_corrinoid:THF_MT_Carnitine_ProlineBetaine_Butyrobetaine_Eubacterium_limosum_ATCC_8486
+MIIIGEKLNGAIPVVKKAIEEKDEAFIRDRAIAQAEAGATYIDVCAGTAPEIELESLKWMMDIVQEAVETPLCIDSPDPEILKAVFPLCKKPGLVNSVSGEGNKMDVLLPLFDDADPTWELVAMTCDNAGIPNTVEKKVELTKMMVEEAKKHNLTPNRIHIDPCVMALSTENHSFLNFKAEIEGIREIYPDIHITSGLSNISFGLPARKLMNQNFMTLSMFVGMDSAVMDPTSRDMMGAIFATDALLGNDRLCRKYSKAFRQGKIGPVQAK
+>METHYL_0005 MV10335_methanogenic_Methanolobus_vulcani_b1d_substrate_glycine_betaine_acrtivase_ramM
+MRIGVAIDLGTSGFRAQKIDLETGEIKKTVITLRNPLPGANVMDHLDFAIHYGLDKAHGLSATAVKNILAELGVNLAEMEKFSICGNPIQLSIFQGIPIEDLAYAGERKKQKYHIEEQNRDARIIPLAEIEGFEEATNCKLFVPPAIKHEVGADALALIVKAGMIESNDVAIATDYGTNAEMALKANGVIYTGSAAAGPALEGQEIEYGSIASPHTISDVEFEGENLRCYVLDKDMTATKGDLVNPKTGEIVEKEELTAKGITGTGVIALIEAGMRNKLIVLPKIQTPDGVIHLQDGIKFTNKDLIEAGRAIGAIRAGHITLCAAAGIDMEELQTAHMSGAAGTYMDAAKAHKVGMIPYNANYVSQIGNTSLTVAREILLSEDRLWELQAIAKEIVGTHVMFATSDAFKEAYMLELAYWNEGMAFKMLQKFLKKKKLPIIGEPSSILKIDRQVERDIPELGEEGLEVLEKVGTYLTMVIEGCEGCHKCVKVCPNGALRMEENGVVKIRTDLCDGANCQRCLHACPDDRFKWENLTVAGK
+>METHYL_0012 RamA_methylamine_corrinoid_binding_protein_reductive_activase_Methanosarcina_barkeri
+MYGIALDLGTSGFRTQLIDLETKETLKTVITMGHPLPGGNVMDHLDFAITTGEDVAHEVIIETIRRMFLQFDIDLSRVERLAVCGNPIQLSLFQNTEIRDLAYAGENKQKMLGVRNVKRDARVFPASEIFGEKYLSNCEIIVPPAIKHEIGADALAMMLETDFLIQPEPSLVTDYGTNAEMALKIGDRIITASAAAGPAIEGQGISSGMLASPGAICDVKPEGQYWRIIVLDREMEKQDAYLIDPVKGEIKDSYGFEAVGITGTGVISAFAMALKGGLIEKFPKLPNGKLILGPGIEITEKDVEEAGKAIGAIRAAHMTLIVESGIKYEDLEYAYMSGASGAYVDAEDARRLGAAPGYAKKIVQFGNTSLALARELVLEKSRLDDVIEIAKKITADHLMMATSETFNNFYLCELSYWTQGMPLETYDQMLELYGLPPLPKILEHVTIEKRVSKDIEEVGSGGLSILKEIGIILEVPVEKCVYCKKCVKECPEAALEIVERDGQRIAKYDSQKCLGTSCRRCVGVCPEDAIDITKLKITAK
+>METHYL_0011 RamQ_promiscuous_MtqC_activase_Carnitine_ProlineBetaine_Butyrobetaine_Eubacterium_limosum_ATCC_8486
+MRVLFPLLEEEIDVSQESLVSDVCASIGLPLNLVCGGKGRCKKCLVNVKENGEMKEVLACQYSVSDGMEIYASREQAASQILETSSNSDLPFDPIVKCYSLNYTDLVTPMCTYDLDVLRKLIPQTIDTPDYSVLKHFSEVYFLEGYERLHVIVSGNRIIDFIPSNEKEKPIYGIAFDIGTTSVVGYLYDITSGCLLNQHSMLNKQIAFGGDVISRIDYAGEGPESLHKIYEAIMETLAEIITQVCKKASIDTKDIYQTVYCGNSTMAHLFLELNPKHLGLAPFLGFCKDAISLKGMDTPLPINPKGTVTFMPLLGGFVGADTTAVLLGLPRDKKMRLMIDLGTNGEIAVGNCDKYYVASTACGPALEGAGLTMGMRGTTGAIEKVGCENGKITYSVIGKTAPQGFCGSGIVDAIAMLFREGLIAKRGNFIKGDALDAHPMKNRFGVDENNQRYFKIVTAGENPEGKDIIITQKDVRAVQLAKAAIYTGCCLLSENYGIKGSDLEEIVIAGAFGNYIDVHNAQFIGLLPKIEGVPVRSIGNGAGTGAQLYLLSKEEAGICNAIPRITTHIELATDPKFVETYMMNTMFGDNVMI
+>METHYL_0048 reductivase_activase,_D._hafniense_DCB2,_AE,_Dhaf_2573
+MGKEITSRIIIGGQNPIAVKNRAWTLMDILTDAGVFLESVCGGQGTCGKCKVRVLSGQVTDGQGNPAEPENDGSYLACRVYPLGQVVLADITQRGVTAKGEIGRIHISLEDRAPVLSKSVVRPTYPTLAQNYSLQEMISNVNELQSQEKQDLHITALRDMALLAQTKTESYTLIHLGDHVTAVEGGDTSSVLYGVAFDIGSTTVAGMLMDMNRGEAVAAAAETNPQSAYGADVISRIKAAEKPEGLKQLSDLIRHCLSTLIRRLCSISGIRVQDIYLVTVVGNSTMEHLLMGISPTSLTIPPYVQAFKSLSPFPPQELSLDIHPGGRVILIPNIASFVGADTTAAILAMDQDLTPKLTLLIDLGTNGEIVLGNRERMIVTSTAAGPAFEGAQLSCGMRATDGAIDDISIQEDVLIRTINAQKPAGICGSGIIKALAEMVRRGIITSSGRFAENSQMAQLSPELRSRIREKEGQREFVLAFAEESANGSDIVITQGDVRELQLVKSSICTGSQILMQTLGVNPEDIEQVFIAGAFGSFVDLDSALAIGLIPIQERNRIRSVGNAAGEGAAKALLSHKHIQRCQAIAEKAEFVELANHPQFQKSFINNLAFPKGGIT
+>METHYL_0042 SECO_corrinoid_binding_protein_reductive_activase/AE,E._limosum_ZL-II,_ELI_0370
+MRVLFPLLEEEIDVSQESLVSDVCASIGLPLNLVCGGKGRCKKCLVNVKENGEMKEVLACQYSVSDGMEIYASREQAASQILETSSNSDLPFDPIVKCYSLNYTDLVTPMCTYDLDVLRKLIPQTIDTPDYSVLKHFSEVYFLEGYERLHVIVSGNRIIDFIPSNEKEKPIYGIAFDIGTTSVVGYLYDITSGCLLNQHSMLNKQIAFGGDVISRIDYAGEGPESLHKIYEAIMETLAEIITQVCKKASIDTKDIYQTVYCGNSTMAHLFLELNPKHLGLAPFLGFCKDAISLKGMDTPLPINPKGTVTFMPLLGGFVGADTTAVLLGLPRDKKMRLMIDLGTNGEIAVGNCDKYYVASTACGPALEGAGLTMGMRGTTGAIEKVGCENGKITYSVIGKTAPQGFCGSGIVDAIAMLFREGLIAKRGNFIKGDALDAHPMKNRFGVDENNQRYFKIVTAGENPEGKDIIITQKDVRAVQLAKAAIYTGCCLLSENYGIKGSDLEEIVIAGAFGNYIDVHNAQFIGLLPKIEGVPVRSIGNGAGTGAQLYLLSKEEAGICNAIPRITTHIELATDPKFVETYMMNTMFGDNVMI
+>METHYL_0032 RamS_MA0489_Methanosarcina_acetivorans_c2a_Q8TSE9
+MYGIALDLGTSGFRAQLIDLETKKVVRTAMTMRHPLPGGNVIDHLDFALEVGEDIANSIILDAVSKIIATFGVDPTCIRKLVVCGNPIQLSLFQNSEIRDLAFAGKNMQRRLGVENVDRSAKVFPASDLFRGVLNLPNCEITVPPAIAHEIGADALAMMIETDFLNRKEVSIVTDYGTNAEMAIKTGDRIITGSAAAGPAIEGQGISCGMIASPGAISDVNLEKKRIEKDIEKDCWRLTVLDEKMEGRPGALIDPVTGETVERGEIEAVGITGTGVIAVIALAMETGLMEQPPKLPDGRLILGNGIEITDADIAEAGKAIGAIRAAQLTLLLEAGVPFEELENVYMSGASGTYVDCRKARKIGSCPDFSKKAVQFGNTSIALARELLLDESRLGEVIALARTIKADHLMMATSETFKNIYTCELSYWTEGMSLKLYKKFFKMYKYPPLPGPVENAVMEKRASKDIEETGNVPVEIVEDVGITIEVPVEGCIQCSRCNEECPENALVTIEKNGSFFASCRTQDCLGTSCRRCVRACPIKAIDFKNIAIQNTSGLQKGSITGGVY
+>METHYL_0018 BbuA_acyl-CoA_dehydrogenase_Emergencia_timonensis
+MDFKLSKEHRALQVKAKEFTEQVLFPYEMECEENNGITPETHKYITQQVMDWGFNATNHSKEHGGQGMTLFEQALCSEQFGMSTGAIWDAIPQPSFPMKFGTQEQIEEYLIPSNQCKRRDAYAITEADAGSDPTQCQTTAVKCDGGYKINGEKWYVTVGNVADFLLVHTHIDGDPEKATVFFVEKDAPGVSVKRTPEFTHHFAFKHPEFTFTDVIVDESKILKGIGEGFNMTKDWFVEARLGIAARCVGGAERVLNVANDWAAERIQGGRPIREYQVIEHMIADMTMEIMAAKSLLYRVCWEISDPDMDRKLKHARASAIKLWCSEMVNHVTDKGVQILGGRGYMRENPVERLWRDQRVDRIWEGTSEIQRNVIGGQIKKRGVELYTGWDYEK
+>METHYL_0019 BbuB_class_III_CoA_transferase _Emergencia_timonensis
+MLPLEGIRILDLTTLSGYCGMELADYGAEVIKVETPSGGDPLRELAPLKNGASPHHVFRDRGKKSVTLNLMHPEGKELFKKLVATADAVLENFTPGTMEKLGLGYEDLSAIKPSLVYGRVSAYGSTGPETDIPQSDLIAQAKSGVMHFTGFPENPPTRIGFSISEHYAASFLASAVCVAIYYARSTGEGQMVETSLCGSAIAVSEDKVITWGADGEDPMRTGNAHPLINPYDILKCKNGYVAMGISSDAQWTKFCKAFNTPEWDEDEKYCSNLVRGYHYFGDLRNKIEDLFSNYTMQEIAAICDENLIPGTMCSTTREALEEPQLQVRNMIVSLEDEKIGKLEMPGKPVKFVGEEEEPLKAAPNLGEHNAEVYGALAIDSVELAHLQQQGVI
+>METHYL_0020 BbuC_class_III_CoA_transferase _Emergencia_timonensis
+MKKRPLEGIKILDFSQVLSAPFCGMLLADMGAEIIKVERPGNGDISREYGPYKNDISLYFCQYNRGKKGVAVDMRSEEGKNVVMDLVSKVDIVIENFKSGTLEKLGIGYEEMLKVNPGLIYGSIAGFGTYGPLSHLPCMDIIAAARSGLVSTTGQGADAPIKPGFSLCDTWAGLQLFRGLTMALLHKQKTGKGLRVDIAMLDCAFYMCEAPVLEHSLTGEFTPRTGNHHPWYAPCGEFVTNDGNAVIAVTREEEWTQLCETLGLSALEQDPRFNNNESRVRNREALIAELEKVTSAMGRYEIEKKLCEVGVPASAVQTLAEFAGNPQTKELKVITEINQPGVGDYTVVNTPIRFSKTPVDPNGVAAGFPGANSKDILNELGYSQEKIDELIDSGAIYQSV
+>METHYL_0021 BbuD_2[4Fe-4S]_ferredoxin_Emergencia_timonensis
+MKCYACTEVCPMKVIGISASGFPEPKSYAYRLCINCGYCVDICVFDALHHKVRKQRSSDPGAAIRRYEEMKKKRKSEQEIK
+>METHYL_0022 BbuE_BCCT_transporter _Emergencia_timonensis
+MENLNKKDRGNIEIGLIIVSVAVLAVFIIFMVLNPETTIRGIGGFFNKMISGLGPVFEVVAFVTFLIGLYLGLGKYGKIRLGDCKPEYSTFSYLAMMLLASLASAALYWSFTEWAFYYEAPGLGMEPHSTEALESSLGYQFFHWGMVNQAMYTVMGVAIAYGVYVRKIKSFQTSAICCSMLGEKVKGKSAIGKVIDFLVIFGVLGALSSSLGLAVPLAAGGLKTLFGIEATPVVQIGIIVVIALVYTFTSYLGTEKGMKVISNAAAGLCIVFLLYVLCAGPTTFILKNIVNSLGHMISKLPRMSLFTDPIENTGFAESWTIYFNAFYLNYVAMMGIFIAKVSKGRTIREVAVATIFGMTAGGWFIFGINGSFSIKTFLDGSADVVGLVNSGVGDAAIYSILKVLPGGATLLPFLILLLIVGFVAPSMDSASLALAETVTKRGTPKMALRIFFCVLLAIIPMAIILSGAGFDPIKQVAIIISAPFMVILVGVEIGLFKWLKHDSRSGLHAKNIALQEKEDHEAFLKEEAELQGEEEETSETA
+>METHYL_0023 BbuF_CoA_thiosesterase_Emergencia_timonensis
+MRSDCIFFCPIRVRYNEVDQQGIVYNGHYVIYTDIAFEEFFRSKGYPYKTLVEEHDSEVCHKKSTYEFFASAYEGDLIEVGMRVLKIGNRSMTIGFEIYREGEDDVIVTCETVYVGYDTKNRASKPISDLMRQLLGA
+>METHYL_0013 BcoAB_gamma-butyrobetainyl-CoA_synthetase/crotonobetainyl-CoA_synthetase_Sinorhizobium_meliloti_Emergencia_timonensis
+MTTPPRSLDRLIRPRSIAVFGGKEARRVIEQCDKMGFAGDIWPVHPREEEILGRRCYRSVADLPEAPDASFVGVNRALTIEIIRDLATRGAGGAVCYASGFREAANELADGNDLQEALVAAAGDMPIVGPNCYGFINMLDGALLWPDQHGMLRVERGVAILTQSSNIACNISMQKRGLPLAYVMTAGNQAQTGLSDIACAVLEDPRVTAVGLHIEGFDSIEALERLAARARELRKPVVTLKVGKSEAAQLATVSHTASLAGNDRVSSALLARLGIGRVDTLPELLETLKLLHLHGPLPSADISSMSCSGGEASLVADAGVRRKVNFRALREEQRQPLRESLGEMVTIANPLDYHTFVWGNREKQTAAFTAMMHGGYALNLIVLDFPRLDRCDAADWVTTCEAVIDSTKATGAVAGIVASLGENMPEETAISLVSAGVVPFFGIDEALGAVETAAAIGAVWAKPAAPPLLRSRPEGGEIVTLSEAEAKDELAAAGVIVPGGRSAATVEEAAAAAESLGFPVALKGLGVAHKTEAGAVRLNLTNRDEVIEAARGMASVASGYLVEKMIAKPVAELIVGAARDAVAGPVLTIGAGGILVELLEDSAILTLPVTEESIRDAIAGLKISRLLDGYRGNPKGDIAALIRTVAAAASYVVANASKLEELDINPIMVLPDGHGAVAADALIRRRK
+>METHYL_0014 BcoD_crotonobetainyl-CoA_hydratase _Sinorhizobium_meliloti_Emergencia_timonensis
+MTPMTGPILTRREGGILEVTIDRPKANAIDLKTSRVMGEIFRDFRDDPELRVAIITGAGEKFFCPGWDLKAAAEGDPVDGDYGVGGFGGMQELRDLNKPIIAAVNGICCGGGLEIALSTDIILAAEHASFALPEIRSGTLADAASIKLPKRIPYHIAMDMLLTGRWLDVVEANRWGFVNEILPAGRLMDRAWELARLLESGPPLVYAAIKEVVRDAEGRDFQTTMNKVTRRQFRTVDVLYSSEDQLEGARAFAEKRDPVWKGR
+>METHYL_0015,METHYL_0017 BcoEF_carnitine_dehydrogenase/thioesterase_Sinorhizobium_meliloti_Emergencia_timonensis
+MTTITKAACIGGGVIGGAWAARFALAGIDVNIFDPHPEAERIIGEVMANAERAYGMLTMAPLPPRGKFTFCRSIQEAVEGVDWIQESVPERLPLKRGVINEIDAAARPDALIGSSTSGLLPSDLQAEMKHPERMFVAHPYNPVYLLPLVELVGGRKTSPETIRRAEEAVAEIGMKGVVIAKEIEAFVGDRLLEALWREALWLIQDDICDTETLDDVMRYSFGMRWAQMGLFETYRIAGGEAGMRHFLAQFGPCLKWPWTKFTDVVDLDDALVEKIGAQSDAQAAGRSIRELERIRDENLVGIMHALKAGDGGKGWGAGKLLADFEKRLWEKGGSPSKSLDASGPLRLVDTKVNAAWVDYNGHMTEHRYLQLFGDTSDALLKVIGVDFAYVEAGHSYYTVETHIRHLGEAKLGQALYTTLQLLSSDEKRIHFFTRIHDAASGDVIATAEQMMLHVDAKAGKSVPAPAEVMAKLKPIAEGHAKLDAPDGAGRHVGQKR
+>METHYL_0016 BcoG_BKACE_enzyme _Sinorhizobium_meliloti_Emergencia_timonensis
+MPLSMNREVFITCAVTGAGDTVSKSSHVPVTPKQIAESAIEAAKAGAAVVHCHVRDPETGAPARRLDLYREVTDRIRSADIDVVLNLTAGMGGDLVFGNVESPFPVDEKGTDMAGATERVAHVAECLPEICTLDCGTMNFSLGDYVMTNTPSMLREMARQMTALGVRPEIEAFDTGHLWFAKQLAEEGLIEDPVLIQLCMGIPWGAPDDLNTFMAMVNNVPSNWTFSAFSIGRNAMAYPAAAVLAGGNVRVGLEDNLYVGKGQLATNAQLVEKAVSVVESMGAKIIGPEEVRRKLKLTKR
+>METHYL_0024 BmoA_glycine_betaine_monooxygenase_Chromohalobacter_salexigens_DSM3403
+MDLLATSALDDPLAAARDATADMLRQRQGDHSLPQPFYNDPRVFALEMREIFEHEWLFVGMTCEIPAKGNYLTVQIGDNPIIVVRGDQGTIHAFHNVCRHRGSRLCTQAKGKVAKLVCPYHQWTYELDGRLLFAGQDMGEDFDLGAHGLKPVAVTHAGGFLFVSLADQPPAIDDFLATLDDYLAPYEMDNVKVAAESNIVEQANWKLVIENNRECYHCNGAHPELLNSLIEYDDTDDPRATPAYRDLVARQQAHWEQQQVPWALKRFGKRNRLTRTPMIEGVVSMTMDGRPASQRLMGRLPNPDMGSLRILHLPNSWNHFMGDHAVVFRVLPLGPQQTLVTTKWLVHRDAQEGVDYDPEWMRKVWDATTDQDRQLAEENQRGINSVAYQPGPYSRTYEFGVIDFVDWYSDTMLSRLDAEAPSLHIVQG
+>METHYL_0025 BmoB_glycine_betaine_NADH-dependent_flavin_reductase_Chromohalobacter_salexigens_DSM3403
+MTQNFFNPVTTQTWTNGRHNVRCVKVIQETWDVRTFCFMADQPVLFFFKPGQFVTLELEIDGEAVMRSYTISSSPSVPYSFSITVKRLPDGRVSNWLHENLQVGSELVVHGPVGDFNVIDYPADKVLMLSGGVGVTPLMSMTRWFFDTNANVDLQFVHSARTPRDIIFHRELEHIFSRIPDFRLHIVCERGDESGEPWAGFRGYLAQAMLELMVPDYLEREIFCCGPTPYMKAVKQVLKSNGFDMSHYHEESFGATPADVRADVEELAEQAEAEMEAVDTADMLQVEFSNSGKSIRIMPEETVHAAAAKLGLHIPKACGMGICGTCKVKKLAGEVTMEHNGGITEEDEADGYILSCCSTPKSHVAIEF
diff --git a/data/methylotrophy/methylotrophy_distillate.tsv b/data/methylotrophy/methylotrophy_distillate.tsv
new file mode 100644
index 00000000..56801896
--- /dev/null
+++ b/data/methylotrophy/methylotrophy_distillate.tsv
@@ -0,0 +1,178 @@
+gene_id	gene_description	module	sheet	header	subheader	fasta
+K25220	"MtxB; Quaternary amine methyltransferase (Glycine betaine methyltransferase, MtgB) [EC:2.1.1.376]"	QA demethylation	METHYL	Catabolism	Anaerobic	
+METHYL_0001	MtgC; Quaternary amine/glycine betaine corrinoid binding protein	QA demethylation	METHYL	Catabolism	Anaerobic	MtgC_DSY3155_Desulfitobacterium_hafniense_Q24SP8;MV8465_Methanolobus_vulcani_b1d_corrinoid_mtgC_homolog_WP_154809803.1
+METHYL_0002	MtgA; Quaternary amine/glycine betaine specific methylcorrinoid:THF methyltransferase	QA demethylation	METHYL	Catabolism	Anaerobic	MtgA_DSY3157_Desulfitobacterium_hafniense_Y51_substrate_glycine_betaine_corrinoid:THF_Q24SP6-1
+METHYL_0003	MV8460; methanogenic glycine betaine:corrinoid methyltransferase	QA demethylation	METHYL	Catabolism	Anaerobic	MV8460_methanogenic_Methanolobus_vulcani_b1d_substrate_glycine_betaine_WP_154809802.1
+METHYL_0004	MV8465; methanogenic glycine betaine corrinoid binding protein	QA demethylation	METHYL	Catabolism	Anaerobic	MV8465_Methanolobus_vulcani_b1d_corrinoid_mtgC_homolog_WP_154809803.1
+K14080	MV10360; methanogenic glycine betaine specific methylcorrinoid:CoM methyltransferase [EC:2.1.1.377]	QA demethylation	METHYL	Catabolism	Anaerobic	
+METHYL_0005	MV10335/RamM; methanogenic corrinoid-protein reductive activase	QA demethylation	METHYL	Catabolism	Anaerobic	MV10335_methanogenic_Methanolobus_vulcani_b1d_substrate_glycine_betaine_acrtivase_ramM
+METHYL_0006	MtpB; proline betaine:corrinoid methyltransferase	QA demethylation	METHYL	Catabolism	Anaerobic	MtpB_proline_betaine:corrinoid_methyltransferase_Eubacterium_limosum_ATCC_8486
+METHYL_0007	MtcB: L-carnitine:corrinoid methyltransferase	QA demethylation	METHYL	Catabolism	Anaerobic	MtcB_L-carnitine:corrinoid_methyltransferase_Eubacterium_limosum_ATCC_8486
+METHYL_0008	MtyB; gamma-butyrobetaine:corrinoid methyltransferase	QA demethylation	METHYL	Catabolism	Anaerobic	MtyB_gamma-butyrobetaine:corrinoid_methyltransferase_Eubacterium_limosum_ATCC_8486
+METHYL_0009	MtqC; quaternary amine promiscuous corrinoid binding protein	QA demethylation	METHYL	Catabolism	Anaerobic	MtqC_promiscuous_QA_corrinoid_Carnitine_ProlineBetaine_Butyrobetaine_Eubacterium_limosum_ATCC_8486
+METHYL_0010	MtqA; quaternary amine promiscuous methylcorrinoid:THF methyltransferase	QA demethylation	METHYL	Catabolism	Anaerobic	MtqA_promiscuous_corrinoid:THF_MT_Carnitine_ProlineBetaine_Butyrobetaine_Eubacterium_limosum_ATCC_8486
+METHYL_0011	RamQ; quaternary amine promiscuous corrinoid protein reductive activase	QA demethylation	METHYL	Catabolism	Anaerobic	RamQ_promiscuous_MtqC_activase_Carnitine_ProlineBetaine_Butyrobetaine_Eubacterium_limosum_ATCC_8486
+K01599	uroporphyrinogen decarboxylase [EC:4.1.1.37] [RN:R03197] (methyltransferase homolog/frequent mis-annotation)	"Heme biosynthesis, animals and fungi, glycine => heme"	METHYL	Catabolism	Anaerobic	
+K14083	"MttB/MtxB; Trimethylamine methyltransferase [EC:2.1.1.250], potentially a quaternary amine enzyme if lacking pyrrolysine"	QA demethylation	METHYL	Catabolism	Anaerobic	
+K14084	MttC; trimethylamine corrinoid binding protein [EC:2.1.1.247]	QA demethylation	METHYL	Catabolism	Anaerobic	
+K16178	MtbB; dimethylamine methyltransferase	DMA demethylation	METHYL	Catabolism	Anaerobic	
+K16179	MtbC; dimethylamine corrinoid binding protein	DMA demethylation	METHYL	Catabolism	Anaerobic	
+K16176	MtmB; monomethylamine methyltransferase	MMA demethylation	METHYL	Catabolism	Anaerobic	
+K16177	MtmC; monomethylamine corrinoid binding protein	MMA demethylation	METHYL	Catabolism	Anaerobic	
+K14082	MtbA; methylamine methylcorrinoid:CoM methyltransferase [EC:2.1.1.247]	Methylamine:CoM methyltransfer	METHYL	Catabolism	Anaerobic	
+METHYL_0012	RamA; methylamine corrinoid binding protein reductive activase	Methylamine:CoM methyltransfer	METHYL	Catabolism	Anaerobic	RamA;_methylamine_corrinoid_binding_protein_reductive_activase_Methanosarcina_barkeri
+K16180	PylB; Methylornithine synthase [EC:5.4.99.58]	Pyrrolysine biosynthesis	METHYL	Amino Acid Biosynthesis	Cofactor/Other_biosynthesis	
+K16181	PylC; Pyrrolysine synthetase [EC:6.3.2.59]	Pyrrolysine biosynthesis	METHYL	Amino Acid Biosynthesis	Cofactor/Other_biosynthesis	
+K16182	PylD; Pyrrolysine synthase [EC:1.4.1.-]	Pyrrolysine biosynthesis	METHYL	Amino Acid Biosynthesis	Cofactor/Other_biosynthesis	
+K11627	PylS; pyrrolysyl-tRNA synthetase [EC:6.1.1.26]	Pyrrolysine biosynthesis	METHYL	Amino Acid Biosynthesis	Cofactor/Other_biosynthesis	
+K14239	PylT; tRNA-pyl	Pyrrolysine biosynthesis	METHYL	Amino Acid Biosynthesis	Cofactor/Other_biosynthesis	
+K02302	CysG; uroporphyrin-III C-methyltransferase/precorrin-2 dehydrogenase/sirohydrochlorin ferrochelatase [ec:2.1.1.107;1.3.1.76;4.99.1.4]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K24866	SirC; preccorin-2 dehydrogenase [EC:1.3.1.76]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02303	CobAM; uroporphyrin-III C-methyltransferase [EC:2.1.1.107]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K22011	CfbA; sirohydrochlorin cobalto/nickelchelatase [EC:4.99.1.3;4.99.1.110]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K03795	CbiX; sirohydrochlorin cobaltochelatase [ED:4.99.1.3]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02190	CbiX; sirohydrochlorin cobaltochelatase [ED:4.99.1.3]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K03394	"CobI, CbiL; precorrin-2/cobalt-factor-2 C20-methyltransferase [EC:2.1.1.130;2.1.1.151]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K21479	CbiH60; cobalt-factor-III methyltransferase	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K05934	"CobJ, CibH; precorrin-3B C17-methyltransferase/cobalt-factor-III methyltransferase [EC:2.1.1.131;2.1.1.272]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K13541	"CbiGH, CobJ; cobalt-precorrin 5A hydrolase/cobalt-factor-III methyltransferase/precorrin-3B C17 methyltransferase [ec:3.7.1.12;2.1.1.272;2.1.1.131]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K05936	"CobM, CbiF; precorrin-4/cobalt-precorrin-4 C11-methyltransferase [EC 2.1.1.133;2.1.1.271]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02189	CbiG; cobalt-precorrin 5A hydrolase [EC:3.7.1.12]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02188	CbiD; cobalt-precorrin 5B hydrolase (C1) methyltransferase [EC:2.1.1.195]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K05895	CobK-CbiJ; precorrin-6A/cobalt-precorrin 6A reductase [EC:1.3.1.54;1.3.1.106]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02192	CbiT; cobalt-precorrin-6B (C15)-methyltransferase[EC:2.1.1.196]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K00595	"CobL, CbiET; precorrin-6B C5, 15-methyltransferase/cobalt-precorrin-6B C5,C15-methyltransferase [EC:2.1.1.132,2.1.1.289,2.1.1.196]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02232	"cobQ, cbiP; adenosylcobyric acid synthase [EC:6.3.5.10]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02231	"CobP, CobU; adenosylcobinamide kinase/adenosylcobinamide phosphate guanylyltransferase [EC:2.7.1.156;2.7.7.62]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02233	"E2.7.8.26, cobS, cobV; adenosylcobinamide-GDP ribazoletransferase [EC:2.7.8.26]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K00798	"MMAB, pduO; cob(I)alamin adenosyltransferase [EC:2.5.1.17]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K19221	"cobA, btuR; cob(I)alamin adenosyltransferase [EC:2.5.1.17]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K19712	cobY; adenosylcobinamide-phosphate guanylyltransferase [EC:2.7.7.62]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02227	"cbiB, cobD; adenosylcobinamide-phosphate synthase [EC:6.3.1.10]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02225	"cobC1, cobC; cobalamin biosynthetic protein"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K13786	"cobR; cob(II)yrinic acid a,c-diamide reductase [EC:1.16.8.1]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K03399	CbiE; cobalt-precorrin-7 (C5)-methyltransferase [EC 2.1.1.289]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K06042	"CobH, CbiC; precorrin-8X/cobalt-precorrin08 methylmutase [EC:5.4.99.61]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02224	"CobB, CbiA; cobyrinic acid a,c-diamide synthase [EC:6.3.5.9;6.2.5.11]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K13540	CobIJ; precorrin-2 C20-methyltransferase/precorrin-3B C17-methyltransferase [EC:2.1.1.130;2.1.1.131]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02229	CobG; precorrin 3B synthase [EC:1.14.13.83]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02228	CobF; precorrin-6A synthase [EC:2.1.1.152]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02230	CobN; cobaltochelatase [EC:6.6.1.2]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K09882	CobS; cobaltochelatase [EC:6.6.1.2]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K09883	CobT; cobaltochelatase [EC:6.6.1.2]	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02226	"CobC, PhpB; alpha-ribazole phosphatase [EC:3.1.3.73]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K22316	"RhnA, CobC; ribonuclease h/adenosylcobalamin/alpha-ribazole phosphatase [EC:3.1.26.4;3.1.3.73]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K00768	"CobU, CobT; nicotinate-nucleotide-dimethylbenzimidazole phosphoribosyltransferase [EC:2.4.2.21]"	Cobalamin biosynthesis	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K16092	BtuB; vitamin-B12 transporter	Cobalamin uptake	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K06073	BtuC; vitamin-B12 transport system permease protein	Cobalamin uptake	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K06074	BtuD; vitamin-B12 transport system-ATP binding protein [EC:7.6.2.8]	Cobalamin uptake	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K25028	BtuD; vitamin-B12 transport system-ATP binding protein [EC:7.6.2.8]	Cobalamin uptake	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K00432	BtuE; vitamin-B12 transport system - periplasmic protein	Cobalamin uptake	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K06858	BtuF; vitamin-B12 transport system-substrate binding protein	Cobalamin uptake	METHYL	Cofactors	Cofactor/Other_biosynthesis	
+K02168	BetTS; choline/glycine/proline betaine transport protein	QA transporter	METHYL	Transporter	Transport	
+K03451	TC.BCT; choline/carnitine/betaine/glycine/BCCT transporter 	QA transporter	METHYL	Transporter	Transport	
+K05020	"OpuD, BetL; glycine-betaine transporter"	QA transporter	METHYL	Transporter	Transport	
+K03762	"ProP; Proline/betaine MFS transporter, PPII, proline permease II"	QA transporter	METHYL	Transporter	Transport	
+K03607	ProQ; proline/betaine (ProP effector)	QA transporter	METHYL	Transporter	Transport	
+K02000	ProV; glycine-betaine/proline transport system ATP binding protein [EC:7.6.2.9]	QA transporter	METHYL	Transporter	Transport	
+K02001	ProW; glycine-betaine/proline transport system permease protein	QA transporter	METHYL	Transporter	Transport	
+K02002	ProX; glycine-betaine/proline transport system substrate binding protein	QA transporter	METHYL	Transporter	Transport	
+K05845	OpuC; Osmoprotectant transport system substrate binding protein	QA transporter	METHYL	Transporter	Transport	
+K05846	OpuBD; Osmoprotectant transport system permease	QA transporter	METHYL	Transporter	Transport	
+K05847	OpuA; Osmoprotectant transport system ATP-binding protein [EC:7.6.2.9]	QA transporter	METHYL	Transporter	Transport	
+K18896	GSMT; glycine/sarcosine N-methyltransferase [EC:2.1.1.156]	QA transporter	METHYL	Transporter	Aerobic	
+K18897	SDMT; sarcosine/dimethylglycine N-methyltransferase [EC:2.1.1.157]	QA transporter	METHYL	Transporter	Aerobic	
+K22443	"YeaW; carnitine/QA-promiscuous monooxygenase subunit, YeaW [ED 1.14.13.239]"	QA cleavage to TMA	METHYL	Catabolism	Aerobic	
+K22444	YeaX carnitine/QA-promiscuous monooxygenase reductase subunit [EC 1.14.13.239]	QA cleavage to TMA	METHYL	Catabolism	Aerobic	
+K22443	CntA; carnitine rieske-type oxygenase [EC:1.14.13.239]	QA cleavage to TMA	METHYL	Catabolism	Aerobic	
+K22444	CntB; carnitine rieske-type reductase [EC:1.14.13.239]	QA cleavage to TMA	METHYL	Catabolism	Aerobic	
+K20038	CutC; choline trimethylamine lysae [EC:4.3.99.4]	QA cleavage to TMA	METHYL	Catabolism	Anaerobic	
+K20037	CutD; glycyl-radical activating enzyme [EC:1.97.1.-]	QA cleavage to TMA	METHYL	Catabolism	Anaerobic	
+K01066	aes; actyl esterase (potentially HocS from Pseuodmonas); [EC:3.1.1.28]	Acylcarnitine -> carnitine	METHYL	Catabolism		
+K05245	CaiT; L-carnitine/gamma-butyrobetaine antiporter	Cai operon	METHYL	Carnitine reduction	Anaerobic	
+K08297	CaiA; crotonobetainly-CoA dehydrogenase [EC:1.3.8.13]	Cai operon	METHYL	Carnitine reduction	Anaerobic	
+K08298	CaiB; L-carnitine CoA-transferase [EC:2.8.3.21]	Cai operon	METHYL	Carnitine reduction	Anaerobic	
+K02182	CaiC; carnitine-CoA ligase [EC:6.2.1.48]	Cai operon	METHYL	Carnitine reduction	Anaerobic	
+K08299	CaiD; crotonobetainyl-CoA hydratase [EC:4.2.1.149]	Cai operon	METHYL	Carnitine reduction	Anaerobic	
+K08279	CaiE; carnitine operon protein	Cai operon	METHYL	Carnitine reduction	Anaerobic	
+K08277	CaiF; tanscriptional activator	Cai operon	METHYL	Carnitine reduction	Anaerobic	
+K03521	FixA; electron transfer flavoprotein beta subunit	Fix operon	METHYL	Carnitine reduction	Anaerobic	
+K03522	FixB; electron transfer flavoprotein alpha subunit	Fix operon	METHYL	Carnitine reduction	Anaerobic	
+K00313	FixC; electron transfer flavoprotein-quinone oxidoreductase [EC:1.5.5.-]	Fix operon	METHYL	Carnitine reduction	Anaerobic	
+K03855	FixX; ferredoxin-like protein	Fix operon	METHYL	Carnitine reduction	Anaerobic	
+K00548	metH; cobalamin-dependent methionine synthase [EC:2.1.1.13]	Methionine Biosynthesis	METHYL	Amino Acid Biosynthesis		
+K00471	BBOX1; gamma-butyrobetaine hydroxylase/dioxygenase [EC:1.14.11.1]	Butyrobetaine -> Carnitine -> Glycine betaine	METHYL	Catabolism	Aerobic	
+METHYL_0013	BcoA; gamma-butyrobetainyl-CoA synthetase	Butyrobetaine -> Carnitine -> Glycine betaine	METHYL	Catabolism	Aerobic	BcoAB;_gamma-butyrobetainyl-CoA_synthetase
+METHYL_0014	BcoD; crotonobetainyl-CoA hydratase	Butyrobetaine -> Carnitine -> Glycine betaine	METHYL	Catabolism	Aerobic	BcoD;_crotonobetainyl-CoA_hydratase _Sinorhizobium_meliloti_Emergencia_timonensis
+METHYL_0015	BcoE; carnitine dehydrogenase	Butyrobetaine -> Carnitine -> Glycine betaine	METHYL	Catabolism	Aerobic	BcoEF;_carnitine_dehydrogenase/thioesterase_Sinorhizobium_meliloti_Emergencia_timonensis
+METHYL_0016	BcoG; BKACE enzyme	Butyrobetaine -> Carnitine -> Glycine betaine	METHYL	Catabolism	Aerobic	BcoG;_BKACE_enzyme _Sinorhizobium_meliloti_Emergencia_timonensis
+METHYL_0017	BcoF; thioesterase	Butyrobetaine -> Carnitine -> Glycine betaine	METHYL	Catabolism	Aerobic	BcoEF;_carnitine_dehydrogenase/thioesterase_Sinorhizobium_meliloti_Emergencia_timonensis
+METHYL_0018	BbuA; acyl-CoA dehydrogenase	Butyrobetaine -> TMA	METHYL	Catabolism	Anaerobic	BbuA;_acyl-CoA_dehydrogenase_Emergencia_timonensis
+METHYL_0019	BbuB; class III CoA transferase	Butyrobetaine -> TMA	METHYL	Catabolism	Anaerobic	BbuB;_class_III_CoA_transferase _Emergencia_timonensis
+METHYL_0020	BbuC; class III CoA transferase	Butyrobetaine -> TMA	METHYL	Catabolism	Anaerobic	BbuC;_class_III_CoA_transferase _Emergencia_timonensis
+METHYL_0021	BbuD; 2[4Fe-4S] ferredoxin	Butyrobetaine -> TMA	METHYL	Catabolism	Anaerobic	BbuD;_2[4Fe-4S]_ferredoxin_Emergencia_timonensis
+METHYL_0022	BbuE; BCCT transporter	Butyrobetaine -> TMA	METHYL	Catabolism	Anaerobic	BbuE;_BCCT_transporter _Emergencia_timonensis
+METHYL_0023	BbuF; CoA thiosesterase	Butyrobetaine -> TMA	METHYL	Catabolism	Anaerobic	BbuF;_CoA_thiosesterase_Emergencia_timonensis\
+K00108	BetA; choline dehydrogenase [EC:1.1.99.1]	Choline -> Glycine betaine	METHYL	Catabolism	Aerobic	
+K00130	BetB; betaine-aldehyde dehydrogenase [EC:1.2.1.8]	Choline -> Glycine betaine	METHYL	Catabolism	Aerobic	
+1.1.1.254	DchH; D-carnitine dehydrogenase [EC1.1.1.254]	Carnitine -> Glycine betaine	METHYL	Catabolism	Aerobic	
+K17735	"LcdH, CdhA; L-carnitine dehydrogenase [EC:1.1.1.108]"	Carnitine -> Glycine betaine	METHYL	Catabolism	Aerobic	
+METHYL_0024	BmoA; glycine betaine monooxygenase	Glycine betaine -> dimethylglycine -> -> glycine	METHYL	Catabolism	Aerobic	BmoA;_glycine_betaine_monooxygenase_Chromohalobacter_salexigens_DSM3403
+METHYL_0025	BmoB; glycine betaine NADH-dependent flavin reductase	Glycine betaine -> dimethylglycine -> -> glycine	METHYL	Catabolism	Aerobic	BmoB;_glycine_betaine_NADH-dependent_flavin_reductase_Chromohalobacter_salexigens_DSM3403
+K00479	"GbcA; glycine betaine demehthylae, subunit A"	Glycine betaine -> dimethylglycine -> -> glycine	METHYL	Catabolism	Aerobic	
+K21832	"GbcB; glycine betaine demethylase, subunit B"	Glycine betaine -> dimethylglycine -> -> glycine	METHYL	Catabolism	Aerobic	
+K00544	BHMT; betaine-homocysteine methyltransferase [EC:2.1.1.5]	Glycine betaine -> dimethylglycine -> -> glycine	METHYL	Catabolism	Aerobic	
+K24003	Stc2; stachydrine N-demethylase	Proline betaine --> N-methylproline	METHYL	Catabolism	Aerobic	
+K22551	hpba; N-methyl-L-proline demethylase [EC:1.5.3.-]	Proline betaine --> N-methylproline -> proline	METHYL	Catabolism	Aerobic	
+K21579	GrdH; betaine reductase complex component B subunit beta [EC:1.21.4.4]	Glycine betaine -> TMA	METHYL	Catabolism	Aerobic	
+K21578	GrdI; betaine reductase complex component B subunit alpha [EC:1.21.4.4]	Glycine betaine -> TMA	METHYL	Catabolism	Aerobic	
+K10670	GrdA; glycine/sarcosine/betaine reductase complex component A [EC:1.21.4.2;1.21.4.3;1.21.4.4]	Glycine betaine -> TMA	METHYL	Catabolism	Aerobic	
+K21576	GrdD; glycine/sarcosine/betaine reductase complex component C subunit alpha [EC:1.21.4.2;1.21.4.3;1.21.4.4]	Glycine betaine -> TMA	METHYL	Catabolism	Aerobic	
+K21577	GrdC;  glycine/sarcosine/betaine reductase complex component C subunit beta [EC:1.21.4.2;1.21.4.3;1.21.4.4]	Glycine betaine -> TMA	METHYL	Catabolism	Aerobic	
+K10672	GrdB; glycine reductase complex component B subunit gamma [EC:1.21.4.2]	Glycine betaine -> TMA	METHYL	Catabolism	Aerobic	
+K10671	GrdE; glycine reductase complex component B subunit alpha and beta [EC:1.21.4.2]	Glycine betaine -> TMA	METHYL	Catabolism	Aerobic	
+K21584	GrdF; sarcosine reductase complex component B subunit beta [EC:1.21.4.3]	Glycine betaine -> TMA	METHYL	Catabolism	Aerobic	
+K21583	GrdG; sarcosine reductase complex component B subunit alpha [EC:1.21.4.3]	Glycine betaine -> TMA	METHYL	Catabolism	Aerobic	
+K15229	MauB; methylamine dehydrogenase heavy chain [EC:1.4.9.1]	Methylamine catabolism	METHYL	Catabolism		
+K15228	MauB; methylamine dehydrogenase light chain [EC:1.4.9.1]	Methylamine catabolism	METHYL	Catabolism		
+K00317	"dmd, tmd; dimethylamine/trimethylamine dehydrogenase [EC:1.5.8.1/2]"	Methylamine catabolism	METHYL	Catabolism		
+K18277	Tmm;  trimethylamine monooxygenase [EC:1.14.13.148]	Methylamine catabolism	METHYL	Catabolism		
+K07811	TorA;  trimethylamine N-oxide reductase [ec:1.7.2.3]	Methylamine catabolism	METHYL	Catabolism		
+14.1.2.32	trimethylamine N-oxide aldolase [EC:4.1.2.32]	Methylamine catabolism	METHYL	Catabolism		
+K22081	MgsA; methylamine-glutamate N-methyltransferase subunit A [EC:2.1.1.21]	Methylamine catabolism	METHYL	Catabolism		
+K08685	QhpA; quinohemoprotein amine dehydrogenase/methylamine dehydrogenase [EC:1.4.9.1]	Methylamine catabolism	METHYL	Catabolism		
+K21310	MddA; methanethiol S-methyltransferase [EC:2.1.1.334]	Methylsulfur methylotrophy	METHYL	Catabolism		
+2.1.1.251	"MtsA; methylsulfide (DMS, MMPA) methyltransferase [EC:2.1.1.251]"	Methylsulfur methylotrophy	METHYL	Catabolism		
+METHYL_0026	"MtsB; methylsulfide (DMS, MMPA) corrinoid binding protein"	Methylsulfur methylotrophy	METHYL	Catabolism		MtsB_corrinoid_protein_Methanosarcina_barkeri_Q48925-1;MtsB_Mx_luminyensis_WP_019177442.1
+METHYL_0027	"dimethylsulfide:corrinoid methyltransferase, MtsD"	Methylsulfur methylotrophy	METHYL	Catabolism		MtsD_MA0859_Methanosarcina_acetivorans_C2A_Q8TSD9-1
+METHYL_0028	"methanethiol:corrinoid methyltransferase, MtsF"	Methylsulfur methylotrophy	METHYL	Catabolism		MtsF_MA4384_Methanosarcina_acetivorans_C2A_Q8THX4
+METHYL_0029	"methylsulfur-compound:corrinoid methyltransferase, MtsH"	Methylsulfur methylotrophy	METHYL	Catabolism		MtsH_MA4558_Methanosarcina_acetivorans_C2A_Q8THF9-1
+METHYL_0030	"methylmercaptopropionate:corrinoid methyltransferase (MT1/2), MtpA"	Methylsulfur methylotrophy	METHYL	Catabolism		MtpA_MA_4165_methylmercaptopropionate:corrinoid_methyltransferase_Methanosarcina_acetivorans
+METHYL_0031	"methylmercaptopropionate corrinoid binding protein, MtpC"	Methylsulfur methylotrophy	METHYL	Catabolism		MtpC_MA_4164_Methanosarcina_acetivorans_C2A_Q8TII5
+METHYL_0032	RamS; reductive activase	Methylsulfur methylotrophy	METHYL	Catabolism		RamS_MA0489_Methanosarcina_acetivorans_c2a_Q8TSE9
+K04480	MtaB; methanol:corrinoid methyltransferase [EC:2.1.1.90]	Methoxy methylotrophy	METHYL	Catabolism		
+K14081	MtaC; methanol corrinoid binding protein	Methoxy methylotrophy	METHYL	Catabolism		
+K14080	MtaA; methanol specific methylcorrinoid:CoM methyltransferase [EC:2.1.1.246]	Methoxy methylotrophy	METHYL	Catabolism		
+PF01208	MtvB; vanillate methyltransferase/O-demethytlase	Methoxy methylotrophy	METHYL	Catabolism		
+METHYL_0033	MtvC; vanillate/O-demethylase corrinoid binding protein	Methoxy methylotrophy	METHYL	Catabolism		MtvC_vanilate_corrinoid/methoxy_corrinoid_Syntrophaceticus_schinkii_A0A0B7MDG8-1;MtvC_Moorella_thermoacetica_Q2RLG8
+METHYL_0034	MtvA; vanillate/O-demethylse specific methylcorrinoid:THF methyltransferase	Methoxy methylotrophy	METHYL	Catabolism		MtvA;_vanillate/O-demethylse_specific_methylcorrinoid:THF_methyltransferase uncultured_Treponema
+O87604	OdmB; vanillate methyltransferase [PFAM:O87604]	Methoxy methylotrophy	METHYL	Catabolism		
+METHYL_0035	"vanillate corrinoid binding protein, OdmA"	Methoxy methylotrophy	METHYL	Catabolism		OdmA_vanillate_corrinoid_Acetobacterium_dehalogenans_O87603-1
+PF00809	OdmD; vanillate specific methylcorrinoid:THF methyltransferase	Methoxy methylotrophy	METHYL	Catabolism		
+PF14574	Odmc; methoxy-specific reductivase activase/Activating Enzyme 	Methoxy methylotrophy	METHYL	Catabolism		
+PF00111	Odmc; methoxy-specific reductivase activase/Activating Enzyme 	Methoxy methylotrophy	METHYL	Catabolism		
+PF17651	Odmc; methoxy-specific reductivase activase/Activating Enzyme 	Methoxy methylotrophy	METHYL	Catabolism		
+METHYL_0036	VdmB; veratrole corrinoid methyltransferase	Methoxy methylotrophy	METHYL	Catabolism		VdmB_veratrole_corrinoid_methyltransferase_Acetobacterium_dehalogenans_Q6W001-1
+METHYL_0037	VdmA; veratole corrinoid binding protein 	Methoxy methylotrophy	METHYL	Catabolism		Vdma_veratrole_corrinoid_Acetobacterium_dehalogenans_Q6W002-1
+METHYL_0038	VdmD; veratrole specific methylcorrinoid:THF methyltransferase	Methoxy methylotrophy	METHYL	Catabolism		VdmD;_veratrole_specific_methylcorrinoid:THF_methyltransferase_Acetobacterium_dehalogenans_Q6W003
+METHYL_0039	"SECO (secoisolariciresinol) corrinoid methyltransferase, E. limosum ZL-II, ELI_2003"	Methoxy methylotrophy	METHYL	Catabolism		"SECO_secoisolariciresinol_corrinoid_methyltransferase,_E._limosum_ZL-II,_ELI_2003"
+METHYL_0040	"SECO (secoisolariciresinol) corrinoid binding protein, E. limosum ZL-II, ELI_2004"	Methoxy methylotrophy	METHYL	Catabolism		"SECO_secoisolariciresinol_corrinoid_E._limosum_ZL-II,_ELI_2004"
+METHYL_0041	"SECO (secoisolariciresinol) methylcorrinoid:THF, E. limosum ZL-II, ELI_2005"	Methoxy methylotrophy	METHYL	Catabolism		"SECO_(secoisolariciresinol)_methylcorrinoid:THF,_E._limosum_ZL-II,_ELI_2005"
+METHYL_0042	"SECO corrinoid binding protein reductive activase/AE,E. limosum ZL-II, ELI_0370"	Methoxy methylotrophy	METHYL	Catabolism		"SECO_corrinoid_binding_protein_reductive_activase/AE,E._limosum_ZL-II,_ELI_0370"
+PF01208	MtoB; methoxy corrinoid methyltransferase	Methoxy methylotrophy	METHYL	Catabolism		
+METHYL_0043	MtoC; methoxy corrinoid binding protein	Methoxy methylotrophy	METHYL	Catabolism		MtoC_AF_0006_Archaeoglobus_fulgidus_DSM_4304_AAB91221.1;MtoC_Archaeoglobus_fulgidus_DSM_4304_methoxy_compounds_including_2-methoxyphenol_AAB91218.1_NCBI_mtac2
+METHYL_0044	MtoA; methoxy specific methylcorrinoid:H4MPT methyltranferase (AF_0009)	Methoxy methylotrophy	METHYL	Catabolism		MtoA_or_mtrH_AF_0009_Archaeoglobus_fulgidus_DSM_4304_WP_010877523.1;MtoA;_methoxy_specific_methylcorrinoid:H4MPT_methyltranferase_(AF_0009) _Archaeoglobus_fulgidus_DSM_4304_ AAB91219.1
+METHYL_0045	"O-demethylase D. hafniense DCB2, methyltransferase Dhaf_4610"	Methoxy methylotrophy	METHYL	Catabolism		O-demethylase_D._hafniense_DCB2_corrinoid_dep_MT_Dhaf_4610_including_vanillate_isovanillate_syringate_guaiacol_methylchloride
+METHYL_0046	"O-demethylase D. hafniense DCB2, corrinoiding binding protien, Dhaf_4611"	Methoxy methylotrophy	METHYL	Catabolism		O-demethylase_D._hafniense_DCB2_corrinoid_Dhaf_4611_including_vanillate_isovanillate_syringate_guaiacol_methylchloride
+METHYL_0047	"O-demethylase D. hafniense DCB2, methylcorrinoid:THF methyltransferase, Dhaf_4612"	Methoxy methylotrophy	METHYL	Catabolism		"O-demethylase_D._hafniense_DCB2,_methylcorrinoid:THF_methyltransferase,_Dhaf_4612"
+METHYL_0048	"reductivase activase, D. hafniense DCB2, AE, Dhaf_2573"	Methoxy methylotrophy	METHYL	Catabolism		"reductivase_activase,_D._hafniense_DCB2,_AE,_Dhaf_2573"
\ No newline at end of file
diff --git a/environment.yaml b/environment.yaml
index c45d89fd..60833cf7 100644
--- a/environment.yaml
+++ b/environment.yaml
@@ -18,4 +18,3 @@ dependencies:
   - networkx
   - ruby
   - parallel
-  - dram
diff --git a/mag_annotator/CONFIG b/mag_annotator/CONFIG
index ffd7360f..bc8aa5c7 100644
--- a/mag_annotator/CONFIG
+++ b/mag_annotator/CONFIG
@@ -1,1 +1,28 @@
-{"description_db": "None", "kegg": null, "kofam": null, "kofam_ko_list": null, "uniref": null, "pfam": null, "pfam_hmm_dat": null, "dbcan": null, "dbcan_fam_activities": null, "viral": null, "peptidase": null, "vogdb": null, "vog_annotations": null, "genome_summary_form": null, "module_step_form": null, "etc_module_database": null, "function_heatmap_form": null, "amg_database": null}
\ No newline at end of file
+{
+  "search_databases": {
+    "kegg": null,
+    "kofam_hmm": null,
+    "kofam_ko_list": null,
+    "uniref": null,
+    "pfam": null,
+    "dbcan": null,
+    "viral": null,
+    "peptidase": null,
+    "vogdb": null
+  },
+  "custom_dbs": null,
+  "database_descriptions": {
+    "pfam_hmm_dat": null,
+    "dbcan_fam_activities": null,
+    "vog_annotations": null
+  },
+  "dram_sheets": {
+    "genome_summary_form": null,
+    "module_step_form": null,
+    "etc_module_database": null,
+    "function_heatmap_form": null,
+    "amg_database": null
+  },
+  "description_db": null,
+  "dram_version": null
+}
diff --git a/mag_annotator/__init__.py b/mag_annotator/__init__.py
index 594fa812..6b4bad8d 100644
--- a/mag_annotator/__init__.py
+++ b/mag_annotator/__init__.py
@@ -1,1 +1,1 @@
-__version__ = '1.3.6'
+__version__ = '1.4.0rc1'
diff --git a/mag_annotator/annotate_bins.py b/mag_annotator/annotate_bins.py
index 97bff3bc..0abeb187 100644
--- a/mag_annotator/annotate_bins.py
+++ b/mag_annotator/annotate_bins.py
@@ -1,11 +1,13 @@
+"""
+Main control point for the annotation process
+"""
 import re
 import io
 import time
-import warnings
+import logging
 from glob import glob
 from functools import partial
 from datetime import datetime
-from typing import Callable
 from skbio.io import read as read_sequence
 from skbio.io import write as write_sequence
 from skbio import Sequence
@@ -14,26 +16,16 @@
 from shutil import rmtree, copy2
 import pandas as pd
 
-
-from mag_annotator.utils import run_process, make_mmseqs_db, merge_files, multigrep, remove_suffix
+from mag_annotator.utils import run_process, make_mmseqs_db, merge_files, \
+    multigrep, remove_suffix, setup_logger, run_hmmscan, sig_scores, get_sig_row, \
+    generic_hmmscan_formater, get_reciprocal_best_hits, get_best_hits, BOUTFMT6_COLUMNS
 from mag_annotator.database_handler import DatabaseHandler
+from mag_annotator.fasta_dup_name_test import fastas_dup_check
 
-# TODO: add ability to take into account multiple best hits as in old_code.py
-# TODO: add real logging
-# TODO: add silent mode
-# TODO: add abx resistance genes
-# TODO: in annotated gene faa checkout out ko id for actual kegg gene id
-# TODO: add ability to handle [] in file names
+MAG_DBS_TO_ANNOTATE = ('kegg', 'kofam_hmm', 'kofam_ko_list', 'uniref', 'peptidase', 'pfam', 'dbcan', 'vogdb') 
 
-MAG_DBS_TO_ANNOTATE = ('kegg', 'kofam', 'kofam_ko_list', 'uniref', 'peptidase', 'pfam', 'dbcan', 'vogdb')
-BOUTFMT6_COLUMNS = ['qId', 'tId', 'seqIdentity', 'alnLen', 'mismatchCnt', 'gapOpenCnt', 'qStart', 'qEnd', 'tStart',
-                    'tEnd', 'eVal', 'bitScore']
-HMMSCAN_ALL_COLUMNS = ['query_id', 'query_ascession', 'query_length', 'target_id', 'target_ascession', 'target_length',
-                       'full_evalue', 'full_score', 'full_bias', 'domain_number', 'domain_count', 'domain_cevalue',
-                       'domain_ievalue', 'domain_score', 'domain_bias', 'target_start', 'target_end', 'alignment_start',
-                       'alignment_end', 'query_start', 'query_end', 'accuracy', 'description']
-HMMSCAN_COLUMN_TYPES = [str, str, int, str, str, int, float, float, float, int, int, float, float, float, float, int,
-                        int, int, int, int, int, float, str]
+# TODO: Bind verbose to logging
+# TODO Exceptions are not fully handled by logging
 
 
 def filter_fasta(fasta_loc, min_len=5000, output_loc=None):
@@ -45,65 +37,17 @@ def filter_fasta(fasta_loc, min_len=5000, output_loc=None):
         write_sequence(kept_seqs, format='fasta', into=output_loc)
 
 
-def run_prodigal(fasta_loc, output_dir, mode='meta', trans_table='11', verbose=False):
+def run_prodigal(fasta_loc, output_dir, logger, mode='meta', trans_table='11', verbose=False):
     """Runs the prodigal gene caller on a given fasta file, outputs resulting files to given directory"""
     output_gff = path.join(output_dir, 'genes.gff')
     output_fna = path.join(output_dir, 'genes.fna')
     output_faa = path.join(output_dir, 'genes.faa')
 
     run_process(['prodigal', '-i', fasta_loc, '-p', mode, '-g', trans_table, '-f', 'gff', '-o', output_gff, '-a',
-                 output_faa, '-d', output_fna], verbose=verbose)
+                 output_faa, '-d', output_fna], logger, verbose=verbose)
     return output_gff, output_fna, output_faa
 
 
-def get_best_hits(query_db, target_db, output_dir='.', query_prefix='query', target_prefix='target',
-                  bit_score_threshold=60, threads=10, verbose=False):
-    """Uses mmseqs2 to do a blast style search of a query db against a target db, filters to only include best hits
-    Returns a file location of a blast out format 6 file with search results
-    """
-    # make query to target db
-    tmp_dir = path.join(output_dir, 'tmp')
-    query_target_db = path.join(output_dir, '%s_%s.mmsdb' % (query_prefix, target_prefix))
-    run_process(['mmseqs', 'search', query_db, target_db, query_target_db, tmp_dir, '--threads', str(threads)],
-                verbose=verbose)
-    # filter query to target db to only best hit
-    query_target_db_top = path.join(output_dir, '%s_%s.tophit.mmsdb' % (query_prefix, target_prefix))
-    run_process(['mmseqs', 'filterdb', query_target_db, query_target_db_top, '--extract-lines', '1'], verbose=verbose)
-    # filter query to target db to only hits with min threshold
-    query_target_db_top_filt = path.join(output_dir, '%s_%s.tophit.minbitscore%s.mmsdb'
-                                         % (query_prefix, target_prefix, bit_score_threshold))
-    run_process(['mmseqs', 'filterdb', '--filter-column', '2', '--comparison-operator', 'ge', '--comparison-value',
-                 str(bit_score_threshold), '--threads', str(threads), query_target_db_top, query_target_db_top_filt],
-                verbose=verbose)
-    # convert results to blast outformat 6
-    forward_output_loc = path.join(output_dir, '%s_%s_hits.b6' % (query_prefix, target_prefix))
-    run_process(['mmseqs', 'convertalis', query_db, target_db, query_target_db_top_filt, forward_output_loc,
-                 '--threads', str(threads)], verbose=verbose)
-    return forward_output_loc
-
-
-def get_reciprocal_best_hits(query_db, target_db, output_dir='.', query_prefix='query', target_prefix='target',
-                             bit_score_threshold=60, rbh_bit_score_threshold=350, threads=10, verbose=False):
-    """Take results from best hits and use for a reciprocal best hits search"""
-    # TODO: Make it take query_target_db as a parameter
-    # create subset for second search
-    query_target_db_top_filt = path.join(output_dir, '%s_%s.tophit.minbitscore%s.mmsdb'
-                                         % (query_prefix, target_prefix, bit_score_threshold))  # I DON'T LIKE THIS
-    query_target_db_filt_top_swapped = path.join(output_dir, '%s_%s.minbitscore%s.tophit.swapped.mmsdb'
-                                                 % (query_prefix, target_prefix, bit_score_threshold))
-    # swap queries and targets in results database
-    run_process(['mmseqs', 'swapdb', query_target_db_top_filt, query_target_db_filt_top_swapped, '--threads',
-                 str(threads)], verbose=verbose)
-    target_db_filt = path.join(output_dir, '%s.filt.mmsdb' % target_prefix)
-    # create a subdatabase of the target database with the best hits as well as the index of the target database
-    run_process(['mmseqs', 'createsubdb', query_target_db_filt_top_swapped, target_db, target_db_filt], verbose=verbose)
-    run_process(['mmseqs', 'createsubdb', query_target_db_filt_top_swapped, '%s_h' % target_db,
-                 '%s_h' % target_db_filt], verbose=verbose)
-
-    return get_best_hits(target_db_filt, query_db, output_dir, target_prefix, query_prefix, rbh_bit_score_threshold,
-                         threads, verbose)
-
-
 def process_reciprocal_best_hits(forward_output_loc, reverse_output_loc, target_prefix='target'):
     """Process the forward and reverse best hits results to find reverse best hits
     Returns the query gene, target gene, if it was a reverse best hit, % identity, bit score and e-value
@@ -169,6 +113,7 @@ def get_basic_description(hits, header_dict, db_name='viral'):
     """Get viral gene full descriptions based on headers (text before first space)"""
     hit_list = list()
     description = list()
+    [hit for hit in hits['%s_hit' % db_name]]
     for hit in hits['%s_hit' % db_name]:
         header = header_dict[hit]
         hit_list.append(hit)
@@ -193,15 +138,15 @@ def get_peptidase_description(peptidase_hits, header_dict):
     return pd.concat([new_df.transpose(), peptidase_hits.drop('peptidase_hit', axis=1)], axis=1, sort=False)
 
 
-def run_mmseqs_profile_search(query_db, pfam_profile, output_loc, output_prefix='mmpro_results', db_handler=None,
+def run_mmseqs_profile_search(query_db, pfam_profile, output_loc, logger, output_prefix='mmpro_results', db_handler=None,
                               threads=10, verbose=False):
     """Use mmseqs to run a search against pfam, currently keeping all hits and not doing any extra filtering"""
     tmp_dir = path.join(output_loc, 'tmp')
     output_db = path.join(output_loc, '%s.mmsdb' % output_prefix)
     run_process(['mmseqs', 'search', query_db, pfam_profile, output_db, tmp_dir, '-k', '5', '-s', '7', '--threads',
-                 str(threads)], verbose=verbose)
+                 str(threads)], logger, verbose=verbose)
     output_loc = path.join(output_loc, '%s_output.b6' % output_prefix)
-    run_process(['mmseqs', 'convertalis', query_db, pfam_profile, output_db, output_loc], verbose=verbose)
+    run_process(['mmseqs', 'convertalis', query_db, pfam_profile, output_db, output_loc], logger, verbose=verbose)
     pfam_results = pd.read_csv(output_loc, sep='\t', header=None, names=BOUTFMT6_COLUMNS)
     if pfam_results.shape[0] > 0:
         pfam_dict = dict()
@@ -220,61 +165,39 @@ def run_mmseqs_profile_search(query_db, pfam_profile, output_loc, output_prefix=
         return pd.DataFrame(columns=[f"{output_prefix}_hits"])
 
 
-def get_sig_row(row):
-    """Check if hmm match is significant, based on dbCAN described parameters"""
-    tstart, tend, tlen, evalue = row[['target_start', 'target_end', 'target_length', 'full_evalue']].values
-    perc_cov = (tend - tstart)/tlen
-    if perc_cov >= .35 and evalue <= 1e-15:
-        return True
-    else:
-        return False
-
-
-# TODO: refactor following to methods to a shared run hmm step and individual get description steps
-def parse_hmmsearch_domtblout(file):
-    df_lines = list()
-    for line in open(file):
-        if not line.startswith('#'):
-            line = line.split()
-            line = line[:22] + [' '.join(line[22:])]
-            df_lines.append(line)
-    hmmsearch_frame = pd.DataFrame(df_lines, columns=HMMSCAN_ALL_COLUMNS)
-    for i, column in enumerate(hmmsearch_frame.columns):
-        hmmsearch_frame[column] = hmmsearch_frame[column].astype(HMMSCAN_COLUMN_TYPES[i])
-    return hmmsearch_frame
-
-
-# continue exit()
-def sig_scores(hits:pd.DataFrame, score_db:pd.DataFrame) -> pd.DataFrame:
-    is_sig = list()
-    for i, frame in hits.groupby('target_id'):
-        row = score_db.loc[i]
-        if row['score_type'] == 'domain':
-            score = frame.domain_score
-        elif row['score_type'] == 'full':
-            score = frame.full_score
-        elif row['score_type'] == '-':
-            continue
-        else:
-            raise ValueError(row['score_type'])
-        frame = frame.loc[score.astype(float) > float(row.threshold)]
-        is_sig.append(frame)
-    if len(is_sig) > 0:
-        return pd.concat(is_sig)
-    else:
-        return pd.DataFrame()
+def find_best_dbcan_hit(genome:str, group:pd.DataFrame):
+    group['perc_cov'] = group.apply(
+        lambda x: (x['target_end'] - x['target_start']) / x['target_length'],
+        axis=1)
+    group.sort_values('perc_cov', inplace=True)
+    group.columns
+    group.sort_values('full_evalue', inplace=True)
+    return group.iloc[0]['target_id']
 
 
 def dbcan_hmmscan_formater(hits:pd.DataFrame,  db_name:str, db_handler=None):
-    hits_sig = hits[hits.apply(get_sig_row, axis=1)]
+    """
+    format the ouput of the dbcan database.
+
+    Note these changes
+    introduce new column for best hit from cazy database- this will be the best hit above the already established threshold (0.35 coverage, e-18 evalue) - then for the distillate pull info from the best hit only
+    introduce new column for corresponding EC number information from sub families (EC numbers are subfamily ECs)
+    Make sure that ids and descriptions are separate (descriptions these are family based)
+    :param hits:
+    :param db_name:
+    :param db_handler:
+    :returns:
+    """
+    hits_sig = hits[hits.apply(partial(get_sig_row, evalue_lim=1e-18), axis=1)]
     if len(hits_sig) == 0:
         # if nothing significant then return nothing, don't get descriptions
         return pd.DataFrame()
-    hits_df = hits_sig.groupby('query_id').apply(
+    hit_groups = hits_sig.groupby('query_id')
+    all_hits = hit_groups.apply(
         lambda x: '; '.join(x['target_id'].apply(lambda y:y[:-4]).unique())
     )
-    hits_df = pd.DataFrame(hits_df)
-    hits_df.columns = [f"{db_name}_id"]
+    hits_df = pd.DataFrame(all_hits)
+    hits_df.columns = [f"{db_name}_ids"]
     def description_pull(x:str):
          id_list = [re.findall('^[A-Z]*[0-9]*', str(x))[0] for x in  x.split('; ')], 
          id_list = [y for x in  id_list for y in x if len(x) > 0]
@@ -282,32 +205,17 @@ def description_pull(x:str):
          description_str = '; '.join(description_list)
          return description_str
     if db_handler is not None:
-        hits_df[f"{db_name}_hits"] = hits_df[f"{db_name}_id"].apply(description_pull)
+        hits_df[f"{db_name}_hits"] = hits_df[f"{db_name}_ids"].apply(description_pull)
+        hits_df[f"{db_name}_subfam_ec"] = hits_df[f"{db_name}_ids"].apply(
+            lambda x:'; '.join(
+                db_handler.get_descriptions(
+                    x.split('; '), 
+                    'dbcan_description', 
+                    description_name='ec'
+                ).values()))
+    hits_df[f'{db_name}_best_hit'] = [find_best_dbcan_hit(*i) for i in hit_groups]
     hits_df.rename_axis(None, inplace=True)
-    return hits_df
-
-
-#TODO decide if we need use_hmmer_thresholds:bool=False
-def generic_hmmscan_formater(hits:pd.DataFrame,  db_name:str, hmm_info_path:str=None, top_hit:bool=True):
-    if hmm_info_path is None:
-        hmm_info = None
-        hits_sig = hits[hits.apply(get_sig_row, axis=1)]
-    else:
-        hmm_info = pd.read_csv(hmm_info_path, sep='\t', index_col=0)
-        hits_sig = sig_scores(hits, hmm_info)
-    if len(hits_sig) == 0:
-        # if nothing significant then return nothing, don't get descriptions
-        return pd.DataFrame()
-    if top_hit:
-        # Get the best hits
-        hits_sig = hits_sig.sort_values('full_evalue').drop_duplicates(subset=["query_id"])
-    hits_df = hits_sig[['target_id', 'query_id']]
-    hits_df.set_index('query_id', inplace=True, drop=True)
-    hits_df.rename_axis(None, inplace=True)
-    hits_df.columns = [f"{db_name}_id"]
-    if hmm_info is not None:
-        hits_df = hits_df.merge(hmm_info[['definition']], how='left', left_on=f"{db_name}_id", right_index=True)
-        hits_df.rename(columns={'definition': f"{db_name}_hits"}, inplace=True)
+    hits_df.columns
     return hits_df
 
 
@@ -362,17 +270,6 @@ def vogdb_hmmscan_formater(hits:pd.DataFrame,  db_name:str, db_handler=None):
     return hits_df
 
 
-def run_hmmscan(genes_faa:str, db_loc:str, db_name:str, output_loc:str, formater:Callable,
-                threads:int=2, db_handler=None, verbose:bool=False):
-    output = path.join(output_loc, f'{db_name}_results.unprocessed.b6')
-    run_process(['hmmsearch', '--domtblout', output, '--cpu', str(threads), db_loc, genes_faa], verbose=verbose)
-    # Parse hmmsearch output
-    if not (path.isfile(output) and stat(output).st_size > 0):
-        return pd.DataFrame()
-    hits = parse_hmmsearch_domtblout(output)
-    return formater(hits)
-
-
 def get_gene_data(fasta_loc):
     """Take the prodigal gene headers and get the scaffold that it came from
     Based on idba_ud 'scaffold_#' scaffold names with gene name after
@@ -460,8 +357,8 @@ def generate_annotated_fasta(input_fasta, annotations, verbosity='short', name=N
 
 def create_annotated_fasta(input_fasta, annotations, output_fasta, verbosity='short', name=None):
     """For use with genes files, added annotations"""
-    write_sequence(generate_annotated_fasta(input_fasta, annotations, verbosity, name),
-                   format='fasta', into=output_fasta)
+    
+    write_sequence( generate_annotated_fasta(input_fasta, annotations, verbosity, name), format='fasta', into=output_fasta)
 
 
 def generate_renamed_fasta(input_fasta, prefix):
@@ -563,10 +460,10 @@ def get_dups(columns):
     return keep
 
 
-def run_trna_scan(fasta, tmp_dir, fasta_name, threads=10, verbose=True):
+def run_trna_scan(fasta, tmp_dir, fasta_name, logger, threads=10, verbose=True):
     """Run tRNAscan-SE on scaffolds and create a table of tRNAs as a separate output"""
     raw_trnas = path.join(tmp_dir, 'raw_trnas.txt')
-    run_process(['tRNAscan-SE', '-G', '-o', raw_trnas, '--thread', str(threads), fasta], verbose=verbose)
+    run_process(['tRNAscan-SE', '-G', '-o', raw_trnas, '--thread', str(threads), fasta], logger, verbose=verbose)
     if path.isfile(raw_trnas) and stat(raw_trnas).st_size > 0:
         trna_frame = pd.read_csv(raw_trnas, sep='\t', skiprows=[0, 2])
         trna_frame.columns = [i.strip() for i in trna_frame.columns]
@@ -579,7 +476,7 @@ def run_trna_scan(fasta, tmp_dir, fasta_name, threads=10, verbose=True):
         trna_frame.insert(0, 'fasta', fasta_name)
         return trna_frame
     else:
-        warnings.warn('No tRNAs were detected, no trnas.tsv file will be created.')
+        logger.warning('No tRNAs were detected, no trnas.tsv file will be created.')
         return None
 
 
@@ -587,8 +484,8 @@ def run_trna_scan(fasta, tmp_dir, fasta_name, threads=10, verbose=True):
 RRNA_COLUMNS = ['fasta', 'begin', 'end', 'strand', 'type', 'e-value', 'note']
 
 
-def run_barrnap(fasta, fasta_name, threads=10, verbose=True):
-    raw_rrna_str = run_process(['barrnap', '--threads', str(threads), fasta], capture_stdout=True, check=False,
+def run_barrnap(fasta, fasta_name, logger, threads=10, verbose=True):
+    raw_rrna_str = run_process(['barrnap', '--threads', str(threads), fasta], logger, capture_stdout=True, check=False,
                                verbose=verbose)
     raw_rrna_table = pd.read_csv(io.StringIO(raw_rrna_str), skiprows=1, sep='\t', header=None,
                                  names=RAW_RRNA_COLUMNS, index_col=0)
@@ -600,7 +497,7 @@ def run_barrnap(fasta, fasta_name, threads=10, verbose=True):
     if len(raw_rrna_table) > 0:
         return pd.DataFrame(rrna_table_rows, index=raw_rrna_table.index, columns=RRNA_COLUMNS).reset_index()
     else:
-        warnings.warn('No rRNAs were detected, no rrnas.tsv file will be created.')
+        logger.warning('No rRNAs were detected, no rrnas.tsv file will be created.')
         return None
 
 
@@ -631,7 +528,7 @@ def make_rrnas_interval(scaffold, row, i):
 
 # TODO: make it take an input and output gff location and not overwrite
 # TODO: for some reason 1 is getting added to intervals when added to gff
-def add_intervals_to_gff(annotations_loc, gff_loc, len_dict, interval_function, groupby_column):
+def add_intervals_to_gff(annotations_loc, gff_loc, len_dict, interval_function, groupby_column, logger):
     # get fasta length dict so we can merge, I'd love to be able to get this from somewhere else
     annotation_frame = pd.read_csv(annotations_loc, sep='\t')
     # process trnas to intervals
@@ -648,7 +545,7 @@ def add_intervals_to_gff(annotations_loc, gff_loc, len_dict, interval_function,
             begin -= 1
             if begin < 0:
                 begin = 0
-                warnings.warn('Interval added to gff started less than zero, set to zero')
+                logger.warning('Interval added to gff started less than zero, set to zero')
             im.add(bounds=[(begin, end)], metadata=metadata)
         annotation_dict[scaffold] = im
     # add trna intervals to gff
@@ -662,25 +559,25 @@ def add_intervals_to_gff(annotations_loc, gff_loc, len_dict, interval_function,
             f.write(gff_intervals.write(io.StringIO(), format='gff3', seq_id=scaffold).getvalue())
 
 
-def do_blast_style_search(query_db, target_db, working_dir, db_handler, formater, start_time,
+def do_blast_style_search(query_db, target_db, working_dir, db_handler, formater, logger,
                           db_name='database', bit_score_threshold=60, rbh_bit_score_threshold=350, threads=10,
                           verbose=False):
     """A convenience function to do a blast style reciprocal best hits search"""
     # Get kegg hits
-    print('%s: Getting forward best hits from %s' % (str(datetime.now() - start_time), db_name))
-    forward_hits = get_best_hits(query_db, target_db, working_dir, 'gene', db_name, bit_score_threshold,
+    logger.info('Getting forward best hits from %s' % db_name)
+    forward_hits = get_best_hits(query_db, target_db, logger, working_dir, 'gene', db_name, bit_score_threshold,
                                  threads, verbose=verbose)
     if stat(forward_hits).st_size == 0:
         return pd.DataFrame()
-    print('%s: Getting reverse best hits from %s' % (str(datetime.now() - start_time), db_name))
-    reverse_hits = get_reciprocal_best_hits(query_db, target_db, working_dir, 'gene', db_name,
+    logger.info('Getting reverse best hits from %s' % db_name)
+    reverse_hits = get_reciprocal_best_hits(query_db, target_db, logger, working_dir, 'gene', db_name,
                                             bit_score_threshold, rbh_bit_score_threshold, threads, verbose=verbose)
     hits = process_reciprocal_best_hits(forward_hits, reverse_hits, db_name)
-    print('%s: Getting descriptions of hits from %s' % (str(datetime.now() - start_time), db_name))
+    logger.info('Getting descriptions of hits from %s' % (db_name))
     if '%s_description' % db_name in db_handler.get_database_names():
         header_dict = db_handler.get_descriptions(hits['%s_hit' % db_name], '%s_description' % db_name)
     else:
-        header_dict = multigrep(hits['%s_hit' % db_name], '%s_h' % target_db, '\x00', working_dir)
+        header_dict = multigrep(hits[f'{db_name}_hit'], f'{target_db}_h', logger, '\x00', working_dir)
     hits = formater(hits, header_dict)
     return hits
 
@@ -699,7 +596,7 @@ def strip_endings(text, suffixes: list):
     return text
 
 
-def process_custom_dbs(custom_fasta_loc, custom_db_name, output_dir, threads=1, verbose=False):
+def process_custom_dbs(custom_fasta_loc, custom_db_name, output_dir, logger, threads=1, verbose=False):
     # if none is passed from argparse then set to tuple of len 0
     mkdir(output_dir)
 
@@ -713,12 +610,12 @@ def process_custom_dbs(custom_fasta_loc, custom_db_name, output_dir, threads=1,
     custom_db_locs = dict()
     for db_name, db_loc in custom_dbs.items():
         custom_db_loc = path.join(output_dir, '%s.custom.mmsdb' % db_name)
-        make_mmseqs_db(db_loc, custom_db_loc, threads=threads, verbose=verbose)
+        make_mmseqs_db(db_loc, custom_db_loc, logger, threads=threads, verbose=verbose)
         custom_db_locs[db_name] = custom_db_loc
     return custom_db_locs
 
 
-def process_custom_hmms(custom_hmm_loc, custom_hmm_name, verbose=False):
+def process_custom_hmms(custom_hmm_loc, custom_hmm_name, logger, verbose=False):
     if custom_hmm_loc is None:
         custom_hmm_loc = ()
     if custom_hmm_name is None:
@@ -727,7 +624,7 @@ def process_custom_hmms(custom_hmm_loc, custom_hmm_name, verbose=False):
         raise ValueError('Lengths of custom db hmm list and custom hmm db name list must be the same.')
     custom_hmm_locs = dict()
     for i in range(len(custom_hmm_name)):
-        run_process(['hmmpress', '-f', custom_hmm_loc[i]], verbose=verbose)  # all are pressed just in case
+        run_process(['hmmpress', '-f', custom_hmm_loc[i]], logger, verbose=verbose)  # all are pressed just in case
         custom_hmm_locs[custom_hmm_name[i]] = custom_hmm_loc[i]
     return custom_hmm_locs
 
@@ -738,7 +635,7 @@ def process_custom_hmm_cutoffs(custom_hmm_cutoffs_loc, custom_hmm_name, verbose=
         raise ValueError("You can't use the custom_hmm_cutoffs_loc argument without the custom_hmm_name and"
                          " custom_hmm_locs aguments specified.")
     if len(custom_hmm_cutoffs_loc) != len(custom_hmm_name):
-        warnings.warn(f"Custom hmm cutoffs and descriptions were only provided to the first {len(custom_hmm_cutoffs_loc)}."
+        logger.warning(f"Custom hmm cutoffs and descriptions were only provided to the first {len(custom_hmm_cutoffs_loc)}."
                       " The rest of the custom hmms will use standard cutoffs and have no descriptions.")
     return {custom_hmm_name[i]:j for i, j in enumerate(custom_hmm_cutoffs_loc)}
 
@@ -766,75 +663,75 @@ def get_trnas(self):
     def get_rrnas(self):
         return pd.read_csv(self.rrnas_loc, sep='\t')
 
-def annotate_orfs(gene_faa, db_handler, tmp_dir, start_time, custom_db_locs=(), custom_hmm_locs=(),
+def annotate_orfs(gene_faa, db_handler, tmp_dir, logger, custom_db_locs=(), custom_hmm_locs=(),
                   custom_hmm_cutoffs_locs=(), bit_score_threshold=60, rbh_bit_score_threshold=350,
                   kofam_use_dbcan2_thresholds=False, threads=10, verbose=False):
     # run reciprocal best hits searches
-    print('%s: Turning genes from prodigal to mmseqs2 db' % str(datetime.now() - start_time))
+    logger.info('Turning genes from prodigal to mmseqs2 db')
     query_db = path.join(tmp_dir, 'gene.mmsdb')
-    make_mmseqs_db(gene_faa, query_db, create_index=True, threads=threads, verbose=verbose)
+    make_mmseqs_db(gene_faa, query_db, logger, create_index=True, threads=threads, verbose=verbose)
 
     annotation_list = list()
 
-    # Get kegg hits
-    if db_handler.db_locs.get('kegg') is not None:
+    if db_handler.config['search_databases'].get('kegg') is not None:
         #TODO Change the get_kegg_description name in function do_blast_style_search to formater
         #TODO think about how this can be consitent with blast and mmseqs
-        annotation_list.append(do_blast_style_search(query_db, db_handler.db_locs['kegg'], tmp_dir,
-                                                     db_handler, get_kegg_description, start_time,
+        annotation_list.append(do_blast_style_search(query_db, db_handler.config['search_databases']['kegg'], tmp_dir,
+                                                     db_handler, get_kegg_description, logger,
                                                      'kegg', bit_score_threshold, rbh_bit_score_threshold, threads,
                                                      verbose))
-    elif db_handler.db_locs.get('kofam') is not None and db_handler.db_locs.get('kofam_ko_list') is not None:
-        print('%s: Getting hits from kofam' % str(datetime.now() - start_time))
+    elif db_handler.config['search_databases'].get('kofam_hmm') is not None and db_handler.config['search_databases'].get('kofam_ko_list') is not None:
+        logger.info('Getting hits from kofam')
         annotation_list.append(run_hmmscan(genes_faa=gene_faa,
-                                           db_loc=db_handler.db_locs['kofam'],
-                                           db_name='kofam',
+                                           db_loc=db_handler.config['search_databases']['kofam_hmm'],
+                                           db_name='kofam_hmm',
                                            output_loc=tmp_dir, #check_impliments
                                            threads=threads, #check_impliments
                                            verbose=verbose,
                                            formater=partial(
                                                kofam_hmmscan_formater,
-                                               hmm_info_path=db_handler.db_locs['kofam_ko_list'],
+                                               hmm_info_path=db_handler.config['search_databases']['kofam_ko_list'],
                                                top_hit=True,
                                                use_dbcan2_thresholds=kofam_use_dbcan2_thresholds
-                                           )))
+                                           ),
+                                           logger=logger))
     else:
-        warnings.warn('No KEGG source provided so distillation will be of limited use.')
+        logger.warning('No KEGG source provided so distillation will be of limited use.')
 
     # Get uniref hits
-    if db_handler.db_locs.get('uniref') is not None:
-        annotation_list.append(do_blast_style_search(query_db, db_handler.db_locs['uniref'], tmp_dir,
+    if db_handler.config['search_databases'].get('uniref') is not None:
+        annotation_list.append(do_blast_style_search(query_db, db_handler.config['search_databases']['uniref'], tmp_dir,
                                                      db_handler, get_uniref_description,
-                                                     start_time, 'uniref', bit_score_threshold,
+                                                     logger, 'uniref', bit_score_threshold,
                                                      rbh_bit_score_threshold, threads, verbose))
 
     # Get viral hits
-    if db_handler.db_locs.get('viral') is not None:
+    if db_handler.config['search_databases'].get('viral') is not None:
         get_viral_description = partial(get_basic_description, db_name='viral')
-        annotation_list.append(do_blast_style_search(query_db, db_handler.db_locs['viral'], tmp_dir,
+        annotation_list.append(do_blast_style_search(query_db, db_handler.config['search_databases']['viral'], tmp_dir,
                                                      db_handler, get_viral_description,
-                                                     start_time, 'viral', bit_score_threshold,
+                                                     logger, 'viral', bit_score_threshold,
                                                      rbh_bit_score_threshold, threads, verbose))
 
     # Get peptidase hits
-    if db_handler.db_locs.get('peptidase') is not None:
-        annotation_list.append(do_blast_style_search(query_db, db_handler.db_locs['peptidase'], tmp_dir,
+    if db_handler.config['search_databases'].get('peptidase') is not None:
+        annotation_list.append(do_blast_style_search(query_db, db_handler.config['search_databases']['peptidase'], tmp_dir,
                                                      db_handler, get_peptidase_description,
-                                                     start_time, 'peptidase', bit_score_threshold,
+                                                     logger, 'peptidase', bit_score_threshold,
                                                      rbh_bit_score_threshold, threads, verbose))
 
     # Get pfam hits
-    if db_handler.db_locs.get('pfam') is not None:
-        print('%s: Getting hits from pfam' % str(datetime.now() - start_time))
-        annotation_list.append(run_mmseqs_profile_search(query_db, db_handler.db_locs['pfam'], tmp_dir,
-                                                         output_prefix='pfam', db_handler=db_handler, threads=threads,
+    if db_handler.config['search_databases'].get('pfam') is not None:
+        logger.info('Getting hits from pfam')
+        annotation_list.append(run_mmseqs_profile_search(query_db, db_handler.config['search_databases']['pfam'], tmp_dir,
+                                                         logger, output_prefix='pfam', db_handler=db_handler, threads=threads,
                                                          verbose=verbose))
 
     # use hmmer to detect cazy ids using dbCAN
-    if db_handler.db_locs.get('dbcan') is not None:
-        print('%s: Getting hits from dbCAN' % str(datetime.now() - start_time))
+    if db_handler.config['search_databases'].get('dbcan') is not None:
+        logger.info('Getting hits from dbCAN')
         annotation_list.append(run_hmmscan(genes_faa=gene_faa,
-                                           db_loc=db_handler.db_locs['dbcan'],
+                                           db_loc=db_handler.config['search_databases']['dbcan'],
                                            db_name='cazy',
                                            output_loc=tmp_dir,
                                            threads=threads,
@@ -842,13 +739,14 @@ def annotate_orfs(gene_faa, db_handler, tmp_dir, start_time, custom_db_locs=(),
                                                dbcan_hmmscan_formater,
                                                db_name='cazy',
                                                db_handler=db_handler
-                                           )))
+                                           ),
+                                           logger=logger))
 
     # use hmmer to detect vogdbs
-    if db_handler.db_locs.get('vogdb') is not None:
-        print('%s: Getting hits from VOGDB' % str(datetime.now() - start_time))
+    if db_handler.config['search_databases'].get('vogdb') is not None:
+        logger.info('Getting hits from VOGDB')
         annotation_list.append(run_hmmscan(genes_faa=gene_faa,
-                                           db_loc=db_handler.db_locs['vogdb'],
+                                           db_loc=db_handler.config['search_databases']['vogdb'],
                                            db_name='vogdb',
                                            threads=threads,
                                            output_loc=tmp_dir,
@@ -856,13 +754,13 @@ def annotate_orfs(gene_faa, db_handler, tmp_dir, start_time, custom_db_locs=(),
                                                vogdb_hmmscan_formater,
                                                db_name='vogdb',
                                                db_handler=db_handler
-                                           )))
-
+                                           ),
+                                           logger=logger))
     for db_name, db_loc in custom_db_locs.items():
-        print('%s: Getting hits from %s' % (str(datetime.now() - start_time), db_name))
+        logger.info('Getting hits from %s' % db_name)
         get_custom_description = partial(get_basic_description, db_name=db_name)
         annotation_list.append(do_blast_style_search(query_db, db_loc, tmp_dir, db_handler,
-                                                     get_custom_description, start_time, db_name,
+                                                     get_custom_description, logger, db_name,
                                                      bit_score_threshold, rbh_bit_score_threshold, threads,
                                                      verbose))
 
@@ -878,26 +776,26 @@ def annotate_orfs(gene_faa, db_handler, tmp_dir, start_time, custom_db_locs=(),
                                                db_name=hmm_name,
                                                hmm_info_path=custom_hmm_cutoffs_locs.get(hmm_name),
                                                top_hit=True
-                                           )))
+                                           ),
+                                           logger=logger))
 
-    # heme regulatory motif count
     annotation_list.append(pd.DataFrame(count_motifs(gene_faa, '(C..CH)'), index=['heme_regulatory_motif_count']).T)
 
     # merge dataframes
-    print('%s: Merging ORF annotations' % str(datetime.now() - start_time))
+    logger.info('Merging ORF annotations')
     annotations = pd.concat(annotation_list, axis=1, sort=False)
-    
+
     # get scaffold data and assign grades
     grades = assign_grades(annotations)
     annotations = pd.concat([grades, annotations], axis=1, sort=False)
-    
+
     return annotations
 
 
-def annotate_fasta(fasta_loc, fasta_name, output_dir, db_handler, min_contig_size=5000, prodigal_mode='meta',
+def annotate_fasta(fasta_loc, fasta_name, output_dir, db_handler, logger, min_contig_size=5000, prodigal_mode='meta',
                    trans_table='11', custom_db_locs=(), custom_hmm_locs=(), custom_hmm_cutoffs_locs=(),
                    bit_score_threshold=60, rbh_bit_score_threshold=350, kofam_use_dbcan2_thresholds=False,
-                   skip_trnascan=False, start_time=datetime.now(), threads=1, rename_bins=True, keep_tmp_dir=False,
+                   skip_trnascan=False, threads=1, rename_bins=True, keep_tmp_dir=False,
                    verbose=False):
     """Annotated a single multifasta file, all file based outputs will be in output_dir"""
     # make temporary directory
@@ -909,16 +807,15 @@ def annotate_fasta(fasta_loc, fasta_name, output_dir, db_handler, min_contig_siz
     filter_fasta(fasta_loc, min_contig_size, filtered_fasta)
 
     if stat(filtered_fasta).st_size == 0:
-        warnings.warn('No sequences were longer than min_contig_size')
+        logger.warning('No sequences were longer than min_contig_size')
         return None
-
     # predict ORFs with prodigal
     # TODO: handle when prodigal returns no genes
-    gene_gff, gene_fna, gene_faa = run_prodigal(filtered_fasta, tmp_dir, mode=prodigal_mode, trans_table=trans_table,
-                                                verbose=verbose)
+    gene_gff, gene_fna, gene_faa = run_prodigal(filtered_fasta, tmp_dir, logger, mode=prodigal_mode, 
+                                                trans_table=trans_table, verbose=verbose)
 
     # annotate ORFs
-    annotations = annotate_orfs(gene_faa, db_handler, tmp_dir, start_time, custom_db_locs, custom_hmm_locs,
+    annotations = annotate_orfs(gene_faa, db_handler, tmp_dir, logger, custom_db_locs, custom_hmm_locs,
                                 custom_hmm_cutoffs_locs, bit_score_threshold, rbh_bit_score_threshold,
                                 kofam_use_dbcan2_thresholds, threads, verbose)
     annotations = pd.concat([get_gene_data(gene_faa), annotations], axis=1, sort=False)
@@ -952,21 +849,21 @@ def annotate_fasta(fasta_loc, fasta_name, output_dir, db_handler, min_contig_siz
     # get tRNAs and rRNAs
     len_dict = {i.metadata['id']: len(i) for i in read_sequence(renamed_scaffolds, format='fasta')}
     if not skip_trnascan:
-        trna_table = run_trna_scan(renamed_scaffolds, tmp_dir, fasta_name, threads=threads, verbose=verbose)
+        trna_table = run_trna_scan(renamed_scaffolds, tmp_dir, fasta_name, logger, threads=threads, verbose=verbose)
         if trna_table is not None:
             trna_loc = path.join(output_dir, 'trnas.tsv')
             trna_table.to_csv(trna_loc, sep='\t', index=False)
-            add_intervals_to_gff(trna_loc, renamed_gffs, len_dict, make_trnas_interval, 'Name')
+            add_intervals_to_gff(trna_loc, renamed_gffs, len_dict, make_trnas_interval, 'Name', logger)
         else:
             trna_loc = None
     else:
         trna_loc = None
 
-    rrna_table = run_barrnap(renamed_scaffolds, fasta_name, threads=threads, verbose=verbose)
+    rrna_table = run_barrnap(renamed_scaffolds, fasta_name, logger,  threads=threads, verbose=verbose)
     if rrna_table is not None:
         rrna_loc = path.join(output_dir, 'rrnas.tsv')
         rrna_table.to_csv(rrna_loc, sep='\t', index=False)
-        add_intervals_to_gff(rrna_loc, renamed_gffs, len_dict, make_rrnas_interval, 'scaffold')
+        add_intervals_to_gff(rrna_loc, renamed_gffs, len_dict, make_rrnas_interval, 'scaffold', logger)
     else:
         rrna_loc = None
 
@@ -985,36 +882,36 @@ def get_fasta_name(fasta_loc):
     return path.splitext(path.basename(remove_suffix(fasta_loc, '.gz')))[0]
 
 
-def annotate_fastas(fasta_locs, output_dir, db_handler, min_contig_size=5000, prodigal_mode='meta', trans_table='11',
-                    bit_score_threshold=60, rbh_bit_score_threshold=350, custom_db_name=(), custom_fasta_loc=(),
-                    custom_hmm_name=(), custom_hmm_loc=(), custom_hmm_cutoffs_loc=(), kofam_use_dbcan2_thresholds=False,
-                    skip_trnascan=False, rename_bins=True, keep_tmp_dir=True, start_time=datetime.now(), threads=10,
-                    verbose=True):
+def annotate_fastas(fasta_locs, output_dir, db_handler, logger, min_contig_size=5000, prodigal_mode='meta', 
+                    trans_table='11', bit_score_threshold=60, rbh_bit_score_threshold=350, custom_db_name=(), 
+                    custom_fasta_loc=(), custom_hmm_name=(), custom_hmm_loc=(), custom_hmm_cutoffs_loc=(), 
+                    kofam_use_dbcan2_thresholds=False, skip_trnascan=False, rename_bins=True, keep_tmp_dir=True,
+                    threads=10, verbose=True):
     # check for no conflicting options/configurations
     tmp_dir = path.join(output_dir, 'working_dir')
     mkdir(tmp_dir)
 
     # setup custom databases to be searched
-    custom_db_locs = process_custom_dbs(custom_fasta_loc, custom_db_name, path.join(tmp_dir, 'custom_dbs'), threads,
-                                        verbose)
-    custom_hmm_locs = process_custom_hmms(custom_hmm_loc, custom_hmm_name)
+    custom_db_locs = process_custom_dbs(custom_fasta_loc, custom_db_name, path.join(tmp_dir, 'custom_dbs'),
+                                        logger, threads, verbose)
+    custom_hmm_locs = process_custom_hmms(custom_hmm_loc, custom_hmm_name, logger)
     custom_hmm_cutoffs_locs= process_custom_hmm_cutoffs(custom_hmm_cutoffs_loc, custom_hmm_name)
-    print('%s: Retrieved database locations and descriptions' % (str(datetime.now() - start_time)))
+    logger.info('Retrieved database locations and descriptions')
 
     # iterate over list of fastas and annotate each individually
     annotations_list = list()
     for fasta_loc in fasta_locs:
         # get name of file e.g. /home/shaffemi/my_genome.fa -> my_genome
         fasta_name = get_fasta_name(fasta_loc)
-        print('%s: Annotating %s' % (str(datetime.now() - start_time), fasta_name))
+        logger.info('Annotating %s' % fasta_name)
         fasta_dir = path.join(tmp_dir, fasta_name)
         mkdir(fasta_dir)
         annotations_list.append(
-            annotate_fasta(fasta_loc, fasta_name, fasta_dir, db_handler, min_contig_size, prodigal_mode, trans_table,
-                           custom_db_locs, custom_hmm_locs, custom_hmm_cutoffs_locs, bit_score_threshold,
-                           rbh_bit_score_threshold, kofam_use_dbcan2_thresholds, skip_trnascan, start_time, threads,
-                           rename_bins, keep_tmp_dir, verbose))
-    print('%s: Annotations complete, processing annotations' % str(datetime.now() - start_time))
+            annotate_fasta(fasta_loc, fasta_name, fasta_dir, db_handler, logger, min_contig_size, prodigal_mode, 
+                           trans_table, custom_db_locs, custom_hmm_locs, custom_hmm_cutoffs_locs, 
+                           bit_score_threshold, rbh_bit_score_threshold, kofam_use_dbcan2_thresholds, 
+                           skip_trnascan, threads, rename_bins, keep_tmp_dir, verbose))
+    logger.info('Annotations complete, processing annotations')
 
     all_annotations = merge_annotations(annotations_list, output_dir)
 
@@ -1024,43 +921,89 @@ def annotate_fastas(fasta_locs, output_dir, db_handler, min_contig_size=5000, pr
     return all_annotations
 
 
-def annotate_bins_cmd(input_fasta, output_dir='.', min_contig_size=5000, prodigal_mode='meta', trans_table='11',
-                      bit_score_threshold=60, rbh_bit_score_threshold=350, custom_db_name=(), custom_fasta_loc=(),
-                      custom_hmm_name=(), custom_hmm_loc=(), custom_hmm_cutoffs_loc=(), use_uniref=False, use_vogdb=False,
-                      kofam_use_dbcan2_thresholds=False, skip_trnascan=False, gtdb_taxonomy=(), checkm_quality=(),
-                      keep_tmp_dir=True, low_mem_mode=False, threads=10, verbose=True):
-    fasta_locs = [j for i in input_fasta for j in glob(i)]
-    if len(fasta_locs) == 0:
-        raise ValueError('Given fasta locations return no paths: %s' % input_fasta)
-    fasta_names = [get_fasta_name(i) for i in fasta_locs]
-    if len(fasta_names) != len(set(fasta_names)):
-        raise ValueError('Genome file names must be unique. At least one name appears twice in this search.')
-    print('%s fastas found' % len(fasta_locs))
-    rename_bins = True
-    annotate_bins(list(set(fasta_locs)), output_dir, min_contig_size, prodigal_mode, trans_table, bit_score_threshold,
-                  rbh_bit_score_threshold, custom_db_name, custom_fasta_loc, custom_hmm_name, custom_hmm_loc,
-                  custom_hmm_cutoffs_loc, use_uniref, use_vogdb, kofam_use_dbcan2_thresholds, skip_trnascan,
-                  gtdb_taxonomy, checkm_quality, rename_bins, keep_tmp_dir, low_mem_mode, threads, verbose)
+def make_fasta_namses_df(fasta_loc):
+    fasta_name = get_fasta_name(fasta_loc)
+    names = [{'fasta': fasta_name, 'seq': seq.metadata['id']} for seq in read_sequence(fasta_loc,format='fasta')]
+    return pd.DataFrame(names)
+
+
+def annotate_fastas_as_one(fasta_locs, output_dir, db_handler, logger, min_contig_size=5000, prodigal_mode='meta', 
+                    trans_table='11', bit_score_threshold=60, rbh_bit_score_threshold=350, custom_db_name=(), 
+                    custom_fasta_loc=(), custom_hmm_name=(), custom_hmm_loc=(), custom_hmm_cutoffs_loc=(), 
+                    kofam_use_dbcan2_thresholds=False, skip_trnascan=False, rename_bins=True, keep_tmp_dir=True,
+                    threads=10, verbose=True):
+    # check for no conflicting options/configurations
+    tmp_dir = path.join(output_dir, 'working_dir')
+    mkdir(tmp_dir)
+
+    # setup custom databases to be searched
+    custom_db_locs = process_custom_dbs(custom_fasta_loc, custom_db_name, path.join(tmp_dir, 'custom_dbs'),
+                                        logger, threads, verbose)
+    custom_hmm_locs = process_custom_hmms(custom_hmm_loc, custom_hmm_name, logger)
+    custom_hmm_cutoffs_locs= process_custom_hmm_cutoffs(custom_hmm_cutoffs_loc, custom_hmm_name)
+    logger.info('Retrieved database locations and descriptions')
+
+    # iterate over list of fastas and annotate each individually
+    annotations_list = list()
+    names = pd.concat([])
+    for fasta_loc in fasta_locs:
+        # get name of file e.g. /home/shaffemi/my_genome.fa -> my_genome
+        fasta_name = get_fasta_name(fasta_loc)
+        logger.info('Annotating %s' % fasta_name)
+        fasta_dir = path.join(tmp_dir, fasta_name)
+        mkdir(fasta_dir)
+        annotations_list.append(
+            annotate_fasta(fasta_loc, fasta_name, fasta_dir, db_handler, logger, min_contig_size, prodigal_mode, 
+                           trans_table, custom_db_locs, custom_hmm_locs, custom_hmm_cutoffs_locs, 
+                           bit_score_threshold, rbh_bit_score_threshold, kofam_use_dbcan2_thresholds, 
+                           skip_trnascan, threads, rename_bins, keep_tmp_dir, verbose))
+    logger.info('Annotations complete, processing annotations')
+    all_annotations = merge_annotations(annotations_list, output_dir)
+
+    # clean up
+    if not keep_tmp_dir:
+        rmtree(tmp_dir)
+    return all_annotations
 
 
 # TODO: Add force flag to remove output dir if it already exists
 # TODO: Add continute flag to continue if output directory already exists
 # TODO: make fasta loc either a string or list to remove annotate_bins_cmd and annotate_called_genes_cmd?
-def annotate_bins(fasta_locs, output_dir='.', min_contig_size=2500, prodigal_mode='meta', trans_table='11',
+def annotate_bins(input_fasta:list, output_dir='.', min_contig_size=2500, prodigal_mode='meta', trans_table='11',
                   bit_score_threshold=60, rbh_bit_score_threshold=350, custom_db_name=(), custom_fasta_loc=(),
-                  custom_hmm_name=(), custom_hmm_loc=(), custom_hmm_cutoffs_loc=(), use_uniref=False, use_vogdb=False,
-                  kofam_use_dbcan2_thresholds=False, skip_trnascan=False, gtdb_taxonomy=(), checkm_quality=(),
-                  rename_bins=True, keep_tmp_dir=True, low_mem_mode=False, threads=10, verbose=True):
+                  custom_hmm_name=(), custom_hmm_loc=(), custom_hmm_cutoffs_loc=(), use_uniref=False, 
+                  use_vogdb=False, kofam_use_dbcan2_thresholds=False, 
+                  skip_trnascan=False, gtdb_taxonomy=(), checkm_quality=(),
+                  rename_bins=True, keep_tmp_dir=True, low_mem_mode=False, threads=10, verbose=True, 
+                  log_file_path:str=None, join_fastas:bool=False, config_loc:str=None):
+    rename_bins = True
+    fasta_locs = [j for i in input_fasta for j in glob(i)]
+    mkdir(output_dir)
+    if log_file_path is None:
+        log_file_path = path.join(output_dir, "annotate.log")
+    logger = logging.getLogger('annotation_log')
+    setup_logger(logger, log_file_path)
+    logger.info(f"The log file is created at {log_file_path}.")
+
+    if len(fasta_locs) == 0:
+        raise ValueError('Given fasta locations return no paths: %s' % input_fasta)
+    fasta_names = [get_fasta_name(i) for i in fasta_locs]
+    if len(fasta_names) != len(set(fasta_names)):
+        raise ValueError('Genome file names must be unique. At least one name appears twice in this search.')
+    logger.info('%s FASTAs found' % len(fasta_locs))
     # set up
-    start_time = datetime.now()
-    print('%s: Annotation started' % str(datetime.now()))
+    db_handler = DatabaseHandler(logger, config_loc)
+    db_handler.filter_db_locs(low_mem_mode, use_uniref,
+                              use_vogdb, master_list=MAG_DBS_TO_ANNOTATE,)
+    db_conf = db_handler.get_settings_str()
+    logger.info(f"Starting the Annotation of Bins with database configuration: \n {db_conf}")
 
     # check inputs
     prodigal_modes = ['train', 'meta', 'single']
     if prodigal_mode not in prodigal_modes:
         raise ValueError('Prodigal mode must be one of %s.' % ', '.join(prodigal_modes))
     elif prodigal_mode in ['normal', 'single']:
-        warnings.warn('When running prodigal in single mode your bins must have long contigs (average length >3 Kbp), '
+        logger.warning('When running prodigal in single mode your bins must have long contigs (average length >3 Kbp), '
                       'be long enough (total length > 500 Kbp) and have very low contamination in order for prodigal '
                       'training to work well.')
 
@@ -1070,16 +1013,11 @@ def annotate_bins(fasta_locs, output_dir='.', min_contig_size=2500, prodigal_mod
         # raise ValueError('Prodigal translation table must be 1-25 or auto')
         raise ValueError('Prodigal translation table must be 1-25')
 
-    # get database locations
-    db_handler = DatabaseHandler()
-    db_handler.filter_db_locs(low_mem_mode, use_uniref, use_vogdb, master_list=MAG_DBS_TO_ANNOTATE)
-
-    mkdir(output_dir)
 
-    all_annotations = annotate_fastas(fasta_locs, output_dir, db_handler, min_contig_size, prodigal_mode, trans_table,
+    all_annotations = annotate_fastas(fasta_locs, output_dir, db_handler, logger, min_contig_size, prodigal_mode, trans_table,
                                       bit_score_threshold, rbh_bit_score_threshold, custom_db_name, custom_fasta_loc,
                                       custom_hmm_name, custom_hmm_loc, custom_hmm_cutoffs_loc,
-                                      kofam_use_dbcan2_thresholds, skip_trnascan, rename_bins, keep_tmp_dir, start_time,
+                                      kofam_use_dbcan2_thresholds, skip_trnascan, rename_bins, keep_tmp_dir,
                                       threads, verbose)
     # if given add taxonomy information
     if len(gtdb_taxonomy) > 0:
@@ -1094,7 +1032,7 @@ def annotate_bins(fasta_locs, output_dir='.', min_contig_size=2500, prodigal_mod
                 taxonomy.append(i)
                 taxonomy_missing_bins.append(i)
         for i in set(taxonomy_missing_bins):
-            warnings.warn('Bin %s was not found in taxonomy file, replaced with bin name.' % i)
+            logger.warning('Bin %s was not found in taxonomy file, replaced with bin name.' % i)
         all_annotations['bin_taxonomy'] = taxonomy
     # if given add quality information
     if len(checkm_quality) > 0:
@@ -1114,52 +1052,83 @@ def annotate_bins(fasta_locs, output_dir='.', min_contig_size=2500, prodigal_mod
                 contamination.append(100)
                 quality_missing_bins.append(i)
             for j in set(quality_missing_bins):
-                warnings.warn('Bin %s was not found in quality file, '
+                logger.warning('Bin %s was not found in quality file, '
                               'replaced with completeness 0 and contamination 100.' % j)
         all_annotations['bin_completeness'] = completeness
         all_annotations['bin_contamination'] = contamination
     all_annotations.to_csv(path.join(output_dir, 'annotations.tsv'), sep='\t')
 
-    print("%s: Completed annotations" % str(datetime.now() - start_time))
+    logger.info("Completed annotations")
 
 
-def annotate_called_genes_cmd(input_faa, output_dir='.', bit_score_threshold=60, rbh_bit_score_threshold=350,
+def annotate_called_genes_cmd(input_faa, output_dir='.', bit_score_threshold=60, 
+                              rbh_bit_score_threshold=350,
                               custom_db_name=(), custom_fasta_loc=(), custom_hmm_loc=(), custom_hmm_name=(),
-                              custom_hmm_cutoffs_loc=(), use_uniref=False, use_vogdb=False,
-                              kofam_use_dbcan2_thresholds=False, rename_genes=True, keep_tmp_dir=True,
-                              low_mem_mode=False, threads=10, verbose=True):
+                              custom_hmm_cutoffs_loc=(), use_uniref=False, log_file_path:str=None,
+                              use_vogdb=False, kofam_use_dbcan2_thresholds=False, rename_genes=True, 
+                              keep_tmp_dir=True, low_mem_mode=False, threads=10, verbose=True, 
+                              config_loc:str=None):
     fasta_locs = glob(input_faa)
+    annotate_called_genes(fasta_locs, output_dir, bit_score_threshold, rbh_bit_score_threshold, 
+                          custom_db_name, custom_fasta_loc, custom_hmm_loc, custom_hmm_name, 
+                          custom_hmm_cutoffs_loc, use_uniref, use_vogdb, kofam_use_dbcan2_thresholds, 
+                          rename_genes, keep_tmp_dir, low_mem_mode, threads, verbose,
+                          config_loc)
+
+def perform_fasta_checks(fasta_locs, logger):
+    """Perform all checks related to integrity of fastas"""
     if len(fasta_locs) == 0:
         raise ValueError('Given fasta locations returns no paths: %s' % input_faa)
-    print('%s fastas found' % len(fasta_locs))
-    annotate_called_genes(fasta_locs, output_dir, bit_score_threshold, rbh_bit_score_threshold, custom_db_name,
-                          custom_fasta_loc, custom_hmm_loc, custom_hmm_name, custom_hmm_cutoffs_loc, use_uniref, use_vogdb,
-                          kofam_use_dbcan2_thresholds, rename_genes, keep_tmp_dir, low_mem_mode, threads, verbose)
-
+    logger.info('%s fastas found' % len(fasta_locs))
+    logger.info("Checking for duplicate names")
+    names = [get_fasta_name(i) for i in fasta_locs]
+    try:
+        if len(names) != len(set(names)):
+            raise ValueError('Genome file names must be unique. At least one name appears twice in this search.')
+        fastas_dup_check(fasta_locs, '>')
+    except ValueError as error:
+        logger.critical(error)
+        raise error
+    logger.info("No duplicate names found")
 
 def annotate_called_genes(fasta_locs, output_dir='.', bit_score_threshold=60, rbh_bit_score_threshold=350,
                           custom_db_name=(), custom_fasta_loc=(), custom_hmm_loc=(), custom_hmm_name=(),
-                          custom_hmm_cutoffs_loc=(), use_uniref=False, use_vogdb=False,
-                          kofam_use_dbcan2_thresholds=False, rename_genes=True, keep_tmp_dir=True, low_mem_mode=False,
-                          threads=10, verbose=True):
-    # set up
-    start_time = datetime.now()
-    print('%s: Annotation started' % str(datetime.now()))
+                          custom_hmm_cutoffs_loc=(), use_uniref=False, 
+                          use_vogdb=False, kofam_use_dbcan2_thresholds=False, rename_genes=True, keep_tmp_dir=True, 
+                          low_mem_mode=False, threads=10, verbose=True, log_file_path:str=None, config_loc:str=None):
+    mkdir(output_dir)
 
+    # Get a logger
+    if log_file_path is None:
+        log_file_path = path.join(output_dir, "annotate.log")
+    logger = logging.getLogger('annotation_log')
+    setup_logger(logger, log_file_path)
+    logger.info(f"The log file is created at {log_file_path}")
     # get database locations
-    db_handler = DatabaseHandler()
+    db_handler = DatabaseHandler(logger, config_loc)
     db_handler.filter_db_locs(low_mem_mode, use_uniref, use_vogdb, master_list=MAG_DBS_TO_ANNOTATE)
+    
+    # Check fastas
+    perform_fasta_checks(fasta_locs, logger)
+
+    logger.info(f"Starting the Annotation of Genes with database configuration: \n {db_handler.get_settings_str()}")
+
+    logger.info("Checking for duplicate names")
+    fasta_names = [get_fasta_name(i) for i in fasta_locs]
+    if len(fasta_names) != len(set(fasta_names)):
+        raise ValueError('Genome file names must be unique. At least one name appears twice in this search.')
+    logger.info("No duplicate names found")
+
 
-    mkdir(output_dir)
     tmp_dir = path.join(output_dir, 'working_dir')
     mkdir(tmp_dir)
 
     # setup custom databases to be searched
-    custom_db_locs = process_custom_dbs(custom_fasta_loc, custom_db_name, path.join(tmp_dir, 'custom_dbs'), threads,
-                                        verbose)
-    custom_hmm_locs = process_custom_hmms(custom_hmm_loc, custom_hmm_name)
+    custom_db_locs = process_custom_dbs(custom_fasta_loc, custom_db_name, path.join(tmp_dir, 'custom_dbs'),
+                                        logger, threads, verbose)
+    custom_hmm_locs = process_custom_hmms(custom_hmm_loc, custom_hmm_name, logger)
     custom_hmm_cutoffs_locs= process_custom_hmm_cutoffs(custom_hmm_cutoffs_loc, custom_hmm_name)
-    print('%s: Retrieved database locations and descriptions' % (str(datetime.now() - start_time)))
+    logger.info('Retrieved database locations and descriptions')
 
     # annotate
     annotation_locs = list()
@@ -1171,11 +1140,12 @@ def annotate_called_genes(fasta_locs, output_dir='.', bit_score_threshold=60, rb
         mkdir(fasta_dir)
 
         # annotate
-        annotations = annotate_orfs(fasta_loc, db_handler, fasta_dir, start_time, custom_db_locs, custom_hmm_locs,
+        annotations = annotate_orfs(fasta_loc, db_handler, fasta_dir, logger, custom_db_locs, custom_hmm_locs,
                                     custom_hmm_cutoffs_locs, bit_score_threshold, rbh_bit_score_threshold,
                                     kofam_use_dbcan2_thresholds, threads, verbose)
 
         annotated_faa = path.join(fasta_dir, 'genes.faa')
+
         create_annotated_fasta(fasta_loc, annotations, annotated_faa, name=fasta_name)
         faa_locs.append(annotated_faa)
 
@@ -1197,10 +1167,11 @@ def annotate_called_genes(fasta_locs, output_dir='.', bit_score_threshold=60, rb
     if not keep_tmp_dir:
         rmtree(tmp_dir)
 
-    print("%s: Completed annotations" % str(datetime.now() - start_time))
+    logger.info("Completed annotations")
 
 
 def merge_annotations(annotations_list, output_dir, write_annotations=False):
+
     # merge annotation dicts
     all_annotations = pd.concat([i.get_annotations() for i in annotations_list if i is not None], sort=False)
     all_annotations = all_annotations.sort_values(['fasta', 'scaffold', 'gene_position'])
@@ -1235,9 +1206,21 @@ def merge_annotations(annotations_list, output_dir, write_annotations=False):
 
 
 def merge_annotations_cmd(input_dirs, output_dir):
-    # make Annotation objects per directory
+
+    mkdir(output_dir)
+    # Get a logger
     annotations_list = list()
+    log_file_path = path.join(output_dir, "annotation.log")
+    logger = logging.getLogger('annotate.log')
+    setup_logger(logger, log_file_path)
+    logger.info(f"The log file is created at {log_file_path}")
+
+    # make Annotation objects per directory
     for i, annotation_dir in enumerate(glob(input_dirs)):
+        if not path.exists(path.join(annotation_dir, "annotations.tsv")):
+            logger.warning("Skipping the fallowing directory because"
+                           f" no 'annotations.tsv' file was found: {annotation_dir}" )
+            continue
         name = 'annotation_%s' % i
         scaffolds = path.join(annotation_dir, 'scaffolds.fna')
         genes_faa = path.join(annotation_dir, 'genes.faa')
@@ -1247,14 +1230,14 @@ def merge_annotations_cmd(input_dirs, output_dir):
         annotations = path.join(annotation_dir, 'annotations.tsv')
         trnas = path.join(annotation_dir, 'trnas.tsv')
         if not path.isfile(trnas):
-            warnings.warn("No trnas.tsv file found in directory %s" % annotation_dir)
+            logger.warning("No trnas.tsv file found in directory %s" % annotation_dir)
             trnas = None
         rrnas = path.join(annotation_dir, 'rrnas.tsv')
         if not path.isfile(rrnas):
-            warnings.warn("No rrnas.tsv file found in directory %s" % annotation_dir)
+            logger.warning("No rrnas.tsv file found in directory %s" % annotation_dir)
             rrnas = None
         annotations_list.append(Annotation(name=name, scaffolds=scaffolds, genes_faa=genes_faa, genes_fna=genes_fna,
                                            gff=gff, gbk=gbk, annotations=annotations, trnas=trnas, rrnas=rrnas))
     # run merge_annotations
-    mkdir(output_dir)
     merge_annotations(annotations_list, output_dir, write_annotations=True)
+
diff --git a/mag_annotator/annotate_vgfs.py b/mag_annotator/annotate_vgfs.py
index dde00942..642ca929 100644
--- a/mag_annotator/annotate_vgfs.py
+++ b/mag_annotator/annotate_vgfs.py
@@ -1,16 +1,20 @@
+"""
+Main control point for the viral annotation process
+"""
 from datetime import datetime
 from os import path, mkdir
 import re
 import warnings
-
+import logging
 import pandas as pd
 import numpy as np
 from skbio.io import read as read_sequence
 from skbio.io import write as write_sequence
 
 from mag_annotator.database_handler import DatabaseHandler
-from mag_annotator.annotate_bins import annotate_fastas
-from mag_annotator.utils import get_ids_from_annotation
+from mag_annotator.annotate_bins import annotate_fastas, get_fasta_name, perform_fasta_checks
+from mag_annotator.utils import setup_logger
+from mag_annotator.summarize_genomes import get_ids_from_annotations_all
 
 VMAG_DBS_TO_ANNOTATE = ('kegg', 'kofam', 'kofam_ko_list', 'uniref', 'peptidase', 'pfam', 'dbcan', 'viral', 'vogdb')
 VIRSORTER_COLUMN_NAMES = ['gene_name', 'start_position', 'end_position', 'length', 'strandedness',
@@ -83,6 +87,7 @@ def remove_bad_chars_virsorter_affi_contigs(virsorter_in: str) -> str:
     or VIRSorter2 affi headers.
 
     :param virsorter_in:
+
         Path to a affi tab file provide for DRAM by VIRSorter or VIRSorter2.
     :returns:
         String of file contents with headers cleaned.
@@ -279,7 +284,7 @@ def calculate_auxiliary_scores(gene_order):
 
 
 def get_metabolic_flags(annotations, metabolic_genes, amgs, verified_amgs, scaffold_length_dict,
-                        length_from_end=5000):
+                        logger, length_from_end=5000):
     flag_dict = dict()
     metabolic_genes = set(metabolic_genes)
     for scaffold, scaffold_annotations in annotations.groupby('scaffold'):
@@ -289,7 +294,7 @@ def get_metabolic_flags(annotations, metabolic_genes, amgs, verified_amgs, scaff
         for gene, row in scaffold_annotations.iterrows():
             # set up
             flags = ''
-            gene_annotations = set(get_ids_from_annotation(pd.DataFrame(row).transpose()).keys())  # TODO: Fix
+            gene_annotations = set(get_ids_from_annotations_all(pd.DataFrame(row).transpose()).keys())  # TODO: Fix
             # is viral
             if 'vogdb_categories' in row.index and not pd.isna(row['vogdb_categories']):
                 if len({'Xr', 'Xs'} & set(row['vogdb_categories'].split(';'))) > 0:
@@ -378,10 +383,10 @@ def get_virsorter_affi_contigs_name(scaffold):
     return get_virsorter_original_affi_contigs_name(scaffold)
 
 
-def add_dramv_scores_and_flags(annotations, db_handler, virsorter_hits=None, input_fasta=None):
+def add_dramv_scores_and_flags(annotations, db_handler, logger, virsorter_hits=None, input_fasta=None):
     # setting up scoring viral genes
-    amg_database_frame = pd.read_csv(db_handler.dram_sheet_locs['amg_database'], sep='\t')
-    genome_summary_form = pd.read_csv(db_handler.dram_sheet_locs['genome_summary_form'], sep='\t', index_col=0)
+    amg_database_frame = pd.read_csv(db_handler.config['dram_sheets']['amg_database'], sep='\t')
+    genome_summary_form = pd.read_csv(db_handler.config['dram_sheets']['genome_summary_form'], sep='\t', index_col=0)
     genome_summary_form = genome_summary_form.loc[genome_summary_form.potential_amg]
 
     # add auxiliary score
@@ -409,7 +414,8 @@ def add_dramv_scores_and_flags(annotations, db_handler, virsorter_hits=None, inp
     amgs = get_amg_ids(amg_database_frame)
     verified_amgs = get_amg_ids(amg_database_frame.loc[amg_database_frame.verified])
     annotations['amg_flags'] = pd.Series(get_metabolic_flags(annotations, metabolic_genes, amgs,
-                                                             verified_amgs, scaffold_length_dict))
+                                                             verified_amgs, scaffold_length_dict,
+                                                             logger))
 
     # downgrade B flag auxiliary scores
     if virsorter_hits is not None:
@@ -419,15 +425,15 @@ def add_dramv_scores_and_flags(annotations, db_handler, virsorter_hits=None, inp
 
     return annotations
 
-
 def annotate_vgfs(input_fasta, virsorter_affi_contigs=None, output_dir='.', min_contig_size=2500, split_contigs=False,
                   prodigal_mode='meta', trans_table='11', bit_score_threshold=60, rbh_bit_score_threshold=350,
                   custom_db_name=(), custom_fasta_loc=(), custom_hmm_loc=(), custom_hmm_cutoffs_loc=(),
                   custom_hmm_name=(), use_uniref=False, kofam_use_dbcan2_thresholds=False, skip_trnascan=False,
                   keep_tmp_dir=True, low_mem_mode=False, threads=10, verbose=True):
-    # set up
-    start_time = datetime.now()
-    print('%s: Viral annotation started' % str(datetime.now()))
+    mkdir(output_dir)
+    log_file_path = path.join(output_dir, "Annotation.log")
+    logger = logging.getLogger('annotation_log')
+    setup_logger(logger, log_file_path)
 
     # check inputs
     prodigal_modes = ['train', 'meta', 'single']
@@ -439,7 +445,7 @@ def annotate_vgfs(input_fasta, virsorter_affi_contigs=None, output_dir='.', min_
                       'training to work well.')
 
     # get database locations
-    db_handler = DatabaseHandler()
+    db_handler = DatabaseHandler(logger)
     db_handler.filter_db_locs(low_mem_mode, use_uniref, True, VMAG_DBS_TO_ANNOTATE)
 
     if virsorter_affi_contigs is not None:
@@ -447,7 +453,11 @@ def annotate_vgfs(input_fasta, virsorter_affi_contigs=None, output_dir='.', min_
     else:
         virsorter_hits = None
 
-    mkdir(output_dir)
+    # Check fastas
+    perform_fasta_checks([input_fasta], logger)
+
+    logger.info(f"Starting the Viral Annotation of Genes with database configuration: \n {db_handler.get_settings_str()}")
+
     if split_contigs:
         # split sequences into separate fastas
         contig_dir = path.join(output_dir, 'vMAGs')
@@ -472,16 +482,16 @@ def annotate_vgfs(input_fasta, virsorter_affi_contigs=None, output_dir='.', min_
 
     # annotate vMAGs
     rename_bins = False
-    annotations = annotate_fastas(contig_locs, output_dir, db_handler, min_contig_size, prodigal_mode, trans_table,
+    annotations = annotate_fastas(contig_locs, output_dir, db_handler, logger, min_contig_size, prodigal_mode, trans_table,
                                   bit_score_threshold, rbh_bit_score_threshold, custom_db_name, custom_fasta_loc,
                                   custom_hmm_name, custom_hmm_loc, custom_hmm_cutoffs_loc, kofam_use_dbcan2_thresholds,
-                                  skip_trnascan, rename_bins, keep_tmp_dir, start_time, threads, verbose)
-    print('%s: Annotations complete, assigning auxiliary scores and flags' % str(datetime.now() - start_time))
+                                  skip_trnascan, rename_bins, keep_tmp_dir, threads, verbose)
+    logging.info('Annotations complete, assigning auxiliary scores and flags')
 
-    annotations = add_dramv_scores_and_flags(annotations, db_handler, virsorter_hits, input_fasta)
+    annotations = add_dramv_scores_and_flags(annotations, db_handler, logger, virsorter_hits, input_fasta)
 
     # write annotations
     annotations.to_csv(path.join(output_dir, 'annotations.tsv'), sep='\t')
 
-    print("%s: Completed annotations" % str(datetime.now() - start_time))
+    logging.info("Completed annotations")
 
diff --git a/mag_annotator/database_handler.py b/mag_annotator/database_handler.py
index 73df049a..0de460cf 100644
--- a/mag_annotator/database_handler.py
+++ b/mag_annotator/database_handler.py
@@ -1,22 +1,27 @@
-from os import path, remove
+from os import path, remove, getenv
 from pkg_resources import resource_filename
 import json
 import gzip
+import logging
 from shutil import copy2
 import warnings
-
 from sqlalchemy import create_engine
 from sqlalchemy.orm import sessionmaker
 
+from datetime import datetime
+from functools import partial
+
 import pandas as pd
 
+from mag_annotator import __version__ as current_dram_version
 from mag_annotator.database_setup import TABLE_NAME_TO_CLASS_DICT, create_description_db
-from mag_annotator.utils import divide_chunks
+from mag_annotator.utils import divide_chunks, setup_logger
 
-SEARCH_DATABASES = ('kegg', 'kofam', 'kofam_ko_list', 'uniref', 'pfam', 'dbcan', 'viral', 'peptidase', 'vogdb')
+SEARCH_DATABASES = {'kegg', 'kofam_hmm', 'kofam_ko_list', 'uniref', 'pfam', 'dbcan', 
+                    'viral', 'peptidase', 'vogdb' }
 DRAM_SHEETS = ('genome_summary_form', 'module_step_form', 'etc_module_database', 'function_heatmap_form',
-               'amg_database')
-DATABASE_DESCRIPTIONS = ('pfam_hmm_dat', 'dbcan_fam_activities', 'vog_annotations')
+                'amg_database')
+DATABASE_DESCRIPTIONS = ('pfam_hmm', 'dbcan_fam_activities', 'vog_annotations')
 
 # TODO: store all sequence db locs within database handler class
 # TODO: store scoring information here e.g. bitscore_threshold, hmm cutoffs
@@ -26,116 +31,213 @@
 
 
 def get_config_loc():
-    return path.abspath(resource_filename('mag_annotator', 'CONFIG'))
+    loc = getenv('DRAM_CONFIG_LOCATION')
+    if loc:
+        return loc
+    else:
+        return path.abspath(resource_filename('mag_annotator', 'CONFIG'))
+
 
+def clear_dict(val):
+    if isinstance(val, dict):
+        return {k: clear_dict(v) for k, v in val.items()}
+    else:
+        return None
+    
 
 class DatabaseHandler:
-    def __init__(self, config_loc=None):
+
+    def __init__(self, logger, config_loc=None):
+        # read in new configuration 
+        # TODO: validate config file after reading it in
         if config_loc is None:
             config_loc = get_config_loc()
 
-        # read in configuration # TODO: validate config file after reading it in
         self.config_loc = config_loc
-        config = json.loads(open(config_loc).read())
-        self.db_locs = {key: value for key, value in config.items() if key in SEARCH_DATABASES}
-        self.db_description_locs = {key: value for key, value in config.items() if key in DATABASE_DESCRIPTIONS}
-        self.dram_sheet_locs = {key: value for key, value in config.items() if key in DRAM_SHEETS}
+        conf = json.loads(open(self.config_loc).read())
+        if len(conf) == 0:
+            logger.warn('There is no config information in the provided file')
+            self.clear_config(write_config=False)
+        if 'dram_version' not in conf:
+            warnings.warn("The DRAM version in your config is empty."
+                          " This may not be a problem, but if this"
+                          " import fails then you should check that"
+                          " the origin of the file is valid.")
+            self.__construct_from_dram_pre_1_4_0(conf)
+        else: 
+            conf_version = conf.get('dram_version')
+            if conf_version is None:
+                db_handler = self.__construct_from_dram_pre_1_4_0(conf)
+            elif conf_version not in {current_dram_version, "1.4.0"}: # Known suported versions
+                warnings.warn("The DRAM version in your config is not listed in the versions "
+                              "that are known to work. This may not be a problem, but if this "
+                              "import fails then you should contact suport.")
+            db_handler = self.__construct_default(conf)
+
+        if logger is None:
+            logger = logging.getLogger("database_handler.log")
+            # log_path = self.get_log_path()
+            # setup_logger(logger, log_path)
+            setup_logger(logger)
+            logger.info(f"Logging to console")
+
+        self.logger = logger
+
+    def get_log_path(self):
+        path = self.config.get('log_path')
+        if path is None:
+            path = path.join(self.config_loc, 'database_processing.log')
+        return path
+
+
+    def __construct_default(self, conf:dict):
+        self.config = conf 
 
         # set up description database connection
-        self.description_loc = config.get('description_db')
-        if self.description_loc is None:
+        description_loc = self.config.get('description_db')
+        if description_loc is None:
             self.session = None
-            warnings.warn('Database does not exist at path %s' % self.description_loc)
-        elif not path.exists(self.description_loc):
+            warnings.warn('Database does not exist at path %s' % description_loc)
+        elif not path.exists(description_loc):
             self.session = None
-            warnings.warn('Database does not exist at path %s' % self.description_loc)
+            warnings.warn('Database does not exist at path %s' % description_loc)
         else:
             self.start_db_session()
 
+    def __construct_from_dram_pre_1_4_0(self, config_old):
+        """
+        Import older dram configs that predate 1.3
+
+
+        :param config_old: A config with no dram version so older than 1.3
+        """
+
+        system_config_loc = get_config_loc()
+        self.config = clear_dict(json.loads(open(system_config_loc).read()))
+        self.config_loc = system_config_loc
+
+
+        # read in configuration # TODO: validate config file after reading it in
+        self.config['search_databases'] = {
+            key: value for key, value in config_old.items() if key in SEARCH_DATABASES}
+        self.config['database_descriptions']  = {
+            key: value for key, value in config_old.items() if key in DATABASE_DESCRIPTIONS}
+        self.config['dram_sheets']  = {
+            key: value for key, value in config_old.items() if key in DRAM_SHEETS}
+        self.config["dram_version"] = current_dram_version
+
+        # set up description database connection
+        self.config['description_db'] = config_old.get('description_db')
+        if self.config.get('description_db') is None:
+            self.session = None
+            warnings.warn('Database does not exist at path %s' % self.config.get('description_db'))
+        elif not path.exists(self.config.get('description_db')):
+            self.session = None
+            warnings.warn('Database does not exist at path %s' % self.config.get('description_db'))
+        else:
+            self.start_db_session()
+    
     def start_db_session(self):
-        engine = create_engine('sqlite:///%s' % self.description_loc)
+        engine = create_engine('sqlite:///%s' % self.config.get('description_db'))
         db_session = sessionmaker(bind=engine)
         self.session = db_session()
 
+
     # functions for adding descriptions to tables
     def add_descriptions_to_database(self, description_list, db_name, clear_table=True):
         description_class = TABLE_NAME_TO_CLASS_DICT[db_name]
         if clear_table:
             self.session.query(description_class).delete()
-        self.session.bulk_save_objects([description_class(**i) for i in description_list])  # TODO: try batching
+        # TODO: try batching
+        self.session.bulk_save_objects([description_class(**i) for i in description_list]) 
         self.session.commit()
         self.session.expunge_all()
 
     # functions for getting descriptions from tables
-    def get_description(self, annotation_id, db_name):
+    def get_description(self, annotation_id, db_name, return_ob=False):
         return self.session.query(TABLE_NAME_TO_CLASS_DICT[db_name]).filter_by(id=annotation_id).one().description
 
-    def get_descriptions(self, ids, db_name):
+    def get_descriptions(self, ids, db_name, description_name='description'):
         description_class = TABLE_NAME_TO_CLASS_DICT[db_name]
         descriptions = [
             des 
             for chunk in divide_chunks(list(ids), 499)
             for des in self.session.query(description_class).filter(description_class.id.in_(chunk)).all() 
         ]
+        # [des for des in self.session.query(description_class).filter(description_class.id.in_(list(ids))).all() ]
+        # [i.id for i in self.session.query(TABLE_NAME_TO_CLASS_DICT['dbcan_description']).all()]
         if len(descriptions) == 0:
             warnings.warn("No descriptions were found for your id's. Does this %s look like an id from %s" % (list(ids)[0],
                                                                                                      db_name))
-        return {i.id: i.description for i in descriptions}
+        return {i.id: i.__dict__[description_name] for i in descriptions}
 
     @staticmethod
     def get_database_names():
         return TABLE_NAME_TO_CLASS_DICT.keys()
 
-    def set_database_paths(self, kegg_db_loc=None, kofam_hmm_loc=None, kofam_ko_list_loc=None, uniref_db_loc=None,
-                           pfam_db_loc=None, pfam_hmm_dat=None, dbcan_db_loc=None, dbcan_fam_activities=None,
-                           viral_db_loc=None, peptidase_db_loc=None, vogdb_db_loc=None, vog_annotations=None,
-                           description_db_loc=None, genome_summary_form_loc=None, module_step_form_loc=None,
-                           etc_module_database_loc=None, function_heatmap_form_loc=None, amg_database_loc=None,
-                           write_config=True):
+    def get_settings_str(self):
+        out_str = ""
+        settings = self.config.get('setup_info')
+        if settings is None:
+            raise Warning('there are no settings, the config is corrupted or too old.')
+            return 'there are no settings, the config is corrupted or too old.'
+        for i in ["search_databases", "database_descriptions", "dram_sheets"]:
+            out_str += "\n"
+            for k in self.config.get(i):
+                if settings.get(k) is not None:
+                    out_str += f"\n{settings[k]['name']}:"
+                    for l, w in settings[k].items():
+                        if l =='name':
+                            continue
+                        out_str += f"\n    {l.title()}: {w}"
+        return out_str
+
+
+    def set_database_paths(self, kegg_loc=None, kofam_hmm_loc=None, kofam_ko_list_loc=None, uniref_loc=None,
+                           pfam_loc=None, pfam_hmm_loc=None, dbcan_loc=None, dbcan_fam_activities_loc=None,
+                           dbcan_subfam_ec_loc=None, viral_loc=None, peptidase_loc=None, vogdb_loc=None, 
+                           vog_annotations_loc=None, description_db_loc=None, genome_summary_form_loc=None, 
+                           module_step_form_loc=None, etc_module_database_loc=None, 
+                           function_heatmap_form_loc=None, amg_database_loc=None, write_config=True):
         def check_exists_and_add_to_location_dict(loc, old_value):
             if loc is None:  # if location is none then return the old value
                 return old_value
-            elif path.isfile(loc):  # if location exists return full path
+            if path.isfile(loc):  # if location exists return full path
                 return path.realpath(loc)
             else:  # if the location doesn't exist then raise error
                 raise ValueError("Database location does not exist: %s" % loc)
-        self.db_locs['kegg'] = check_exists_and_add_to_location_dict(kegg_db_loc, self.db_locs.get('kegg'))
-        self.db_locs['kofam'] = check_exists_and_add_to_location_dict(kofam_hmm_loc, self.db_locs.get('kofam'))
-        self.db_locs['kofam_ko_list'] = check_exists_and_add_to_location_dict(kofam_ko_list_loc,
-                                                                              self.db_locs.get('kofam_ko_list'))
-        self.db_locs['uniref'] = check_exists_and_add_to_location_dict(uniref_db_loc, self.db_locs.get('uniref'))
-        self.db_locs['pfam'] = check_exists_and_add_to_location_dict(pfam_db_loc, self.db_locs.get('pfam'))
-
-        self.db_locs['dbcan'] = check_exists_and_add_to_location_dict(dbcan_db_loc, self.db_locs.get('dbcan'))
-
-        self.db_locs['viral'] = check_exists_and_add_to_location_dict(viral_db_loc, self.db_locs.get('viral'))
-        self.db_locs['peptidase'] = check_exists_and_add_to_location_dict(peptidase_db_loc,
-                                                                          self.db_locs.get('peptidase'))
-        self.db_locs['vogdb'] = check_exists_and_add_to_location_dict(vogdb_db_loc, self.db_locs.get('vogdb'))
-
-        self.db_description_locs['pfam_hmm_dat'] = \
-            check_exists_and_add_to_location_dict(pfam_hmm_dat, self.db_description_locs.get('pfam_hmm_dat'))
-        self.db_description_locs['dbcan_fam_activities'] = \
-            check_exists_and_add_to_location_dict(dbcan_fam_activities,
-                                                  self.db_description_locs.get('dbcan_fam_activities'))
-        self.db_description_locs['vog_annotations'] = \
-            check_exists_and_add_to_location_dict(vog_annotations, self.db_description_locs.get('vog_annotations'))
-
-        self.dram_sheet_locs['genome_summary_form'] = \
-            check_exists_and_add_to_location_dict(genome_summary_form_loc,
-                                                  self.dram_sheet_locs.get('genome_summary_form'))
-        self.dram_sheet_locs['module_step_form'] = \
-            check_exists_and_add_to_location_dict(module_step_form_loc, self.dram_sheet_locs.get('module_step_form'))
-        self.dram_sheet_locs['etc_module_database'] = \
-            check_exists_and_add_to_location_dict(etc_module_database_loc,
-                                                  self.dram_sheet_locs.get('etc_module_database'))
-        self.dram_sheet_locs['function_heatmap_form'] = \
-            check_exists_and_add_to_location_dict(function_heatmap_form_loc,
-                                                  self.dram_sheet_locs.get('function_heatmap_form'))
-        self.dram_sheet_locs['amg_database'] = \
-            check_exists_and_add_to_location_dict(amg_database_loc, self.dram_sheet_locs.get('amg_database'))
-
-        self.description_loc = check_exists_and_add_to_location_dict(description_db_loc, self.description_loc)
+        locs = {
+                "search_databases": {
+                  'kegg': kegg_loc,
+                  'kofam_hmm': kofam_hmm_loc,
+                  'kofam_ko_list': kofam_ko_list_loc,
+                  'uniref': uniref_loc,
+                  'pfam': pfam_loc,
+                  'dbcan': dbcan_loc,
+                  'viral': viral_loc,
+                  'peptidase': peptidase_loc,
+                  'vogdb': vogdb_loc,
+                },
+                "database_descriptions": {
+                  'pfam_hmm': pfam_hmm_loc,
+                  'dbcan_fam_activities': dbcan_fam_activities_loc,
+                  'dbcan_subfam_ec': dbcan_subfam_ec_loc,
+                  'vog_annotations': vog_annotations_loc,
+                },
+                "dram_sheets": {
+                  'genome_summary_form': genome_summary_form_loc,
+                  'module_step_form': module_step_form_loc,
+                  'etc_module_database': etc_module_database_loc,
+                  'function_heatmap_form': function_heatmap_form_loc,
+                  'amg_database': amg_database_loc,
+                },
+        }
+
+        self.config.update({i:{
+            k:check_exists_and_add_to_location_dict(locs[i][k], self.config.get(i).get(k)) 
+            for k in locs[i]} for i in locs})
+
+        self.config['description_db'] = check_exists_and_add_to_location_dict(description_db_loc, self.config.get('description_db'))
         self.start_db_session()
 
         if write_config:
@@ -145,10 +247,7 @@ def write_config(self, config_loc=None):
         if config_loc is None:
             config_loc = self.config_loc
         with open(config_loc, 'w') as f:
-            config = {key: value for dict_ in (self.db_locs, self.db_description_locs, self.dram_sheet_locs)
-                      for key, value in dict_.items()}
-            config['description_db'] = self.description_loc
-            f.write(json.dumps(config))
+            f.write(json.dumps(self.config, indent=2))
 
     @staticmethod
     def make_header_dict_from_mmseqs_db(mmseqs_db):
@@ -167,15 +266,16 @@ def make_header_dict_from_mmseqs_db(mmseqs_db):
             else:
                 mmseqs_ids_not_unique.add(header['id'])
         if len(mmseqs_ids_not_unique) > 0:
-            warnings.warn(f'There are {len(mmseqs_ids_not_unique)} non unique headers in {mmseqs_db}! You should definitly investigate this!')
+            warnings.warn(f'There are {len(mmseqs_ids_not_unique)} non unique headers '
+                          f'in {mmseqs_db}! You should definitly investigate this!')
         return mmseqs_headers_split
 
     @staticmethod
-    def process_pfam_descriptions(pfam_hmm_dat):
-        if pfam_hmm_dat.endswith('.gz'):
-            f = gzip.open(pfam_hmm_dat, 'r').read().decode('utf-8')
+    def process_pfam_descriptions(pfam_hmm):
+        if pfam_hmm.endswith('.gz'):
+            f = gzip.open(pfam_hmm, 'r').read().decode('utf-8')
         else:
-            f = open(pfam_hmm_dat).read()
+            f = open(pfam_hmm).read()
         entries = f.strip().split('//')
         description_list = list()
         for i, entry in enumerate(entries):
@@ -193,10 +293,8 @@ def process_pfam_descriptions(pfam_hmm_dat):
         return description_list
 
     @staticmethod
-    def process_dbcan_descriptions(dbcan_fam_activities):
-        f = open(dbcan_fam_activities)
-        description_list = list()
-        for line in f.readlines():
+    def process_dbcan_descriptions(dbcan_fam_activities, dbcan_subfam_ec):
+        def line_reader(line):
             if not line.startswith('#') and len(line.strip()) != 0:
                 line = line.strip().split()
                 if len(line) == 1:
@@ -205,8 +303,24 @@ def process_dbcan_descriptions(dbcan_fam_activities):
                     description = ' '.join(line[1:])
                 else:
                     description = ' '.join(line)
-                description_list.append({'id': line[0], 'description': description.replace('\n', ' ')})
-        return description_list
+                return pd.DataFrame({'id': line[0], 'description': description.replace('\n', ' ')}, index=[0])
+        with open(dbcan_fam_activities) as f:
+            description_data = pd.concat([line_reader(line) for line in f.readlines()])
+        
+        ec_data = (pd.read_csv(dbcan_subfam_ec, sep='\t',names=['id', 'id2','ec'], comment='#')[['id', 'ec']]
+                           .drop_duplicates())
+        ec_data = (pd.concat([ec_data['id'],
+                                     ec_data['ec'].str.split('|', expand=True)]
+                                    ,axis=1)
+                           .melt(id_vars='id',value_name='ec')
+                           .dropna(subset=['ec'])[['id', 'ec']]
+                           .groupby('id')
+                           .apply(lambda x: ','.join(x['ec'].unique()))
+                           )
+        ec_data = pd.DataFrame(ec_data, columns=['ec']).reset_index()
+        data = pd.merge(description_data, ec_data, how='outer', on='id').fillna('')
+        return [i.to_dict() for _, i in data.iterrows()]
+
 
     @staticmethod
     def process_vogdb_descriptions(vog_annotations):
@@ -217,131 +331,146 @@ def process_vogdb_descriptions(vog_annotations):
         return annotations_list
 
     # TODO: Make option to build on description database that already exists?
-    def populate_description_db(self, output_loc=None, update_config=True):
-        if self.description_loc is None and output_loc is None:  # description db location must be set somewhere
+    def populate_description_db(self, output_loc=None, select_db=None, update_config=True,  erase_old_db=False):
+        if self.config.get('description_db') is None and output_loc is None:  # description db location must be set somewhere
+            self.logger.critical('Must provide output location if description db location is not set in configuration')
             raise ValueError('Must provide output location if description db location is not set in configuration')
         if output_loc is not None:  # if new description db location is set then save it there
-            self.description_loc = output_loc
+            self.config['description_db']= output_loc
             self.start_db_session()
-        if path.exists(self.description_loc):
-            remove(self.description_loc)
-        create_description_db(self.description_loc)
-
-        # fill database
-        if self.db_locs.get('kegg') is not None:
-            self.add_descriptions_to_database(self.make_header_dict_from_mmseqs_db(self.db_locs['kegg']), 'kegg_description',
-                                              clear_table=True)
-        if self.db_locs.get('uniref') is not None:
-            self.add_descriptions_to_database(self.make_header_dict_from_mmseqs_db(self.db_locs['uniref']) ,
-                                              'uniref_description', clear_table=True)
-        if self.db_description_locs.get('pfam_hmm_dat') is not None:
-            self.add_descriptions_to_database(self.process_pfam_descriptions(self.db_description_locs['pfam_hmm_dat']),
-                                              'pfam_description', clear_table=True)
-        if self.db_description_locs.get('dbcan_fam_activities') is not None:
-            self.add_descriptions_to_database(self.process_dbcan_descriptions(
-                self.db_description_locs['dbcan_fam_activities']), 'dbcan_description', clear_table=True)
-        if self.db_locs.get('viral') is not None:
-            self.add_descriptions_to_database(self.make_header_dict_from_mmseqs_db(self.db_locs['viral']),
-                                              'viral_description', clear_table=True)
-        if self.db_locs.get('peptidase') is not None:
-            self.add_descriptions_to_database(self.make_header_dict_from_mmseqs_db(self.db_locs['peptidase']),
-                                              'peptidase_description', clear_table=True)
-        if self.db_description_locs.get('vog_annotations') is not None:
+        # I don't think this is needed
+        if path.exists(self.config.get('description_db')) and erase_old_db:
+            remove(self.config.get('description_db'))
+        create_description_db(self.config.get('description_db'))
+        def check_db(db_name, db_function):
+            # TODO add these sorts of checks to a separate function
+            # if self.config.get('search_databases').get(db_name) is None:
+            #     return
+            # if not path.exists(self.config['search_databases'][db_name]):
+            #     logger.warn(f"There is a path for the {db_name} db in the config, but there"
+            #                 " is no file at that path. The path is:"
+            #                 f"{self.config['search_databases'][db_name]}")
+            #     return
             self.add_descriptions_to_database(
-                self.process_vogdb_descriptions(self.db_description_locs['vog_annotations']), 'vogdb_description',
+                db_function(),
+                f'{db_name}_description',
                 clear_table=True)
-
+            self.config['setup_info'][db_name]['description_db_updated'] = \
+                datetime.now().strftime("%m/%d/%Y, %H:%M:%S")
+            self.logger.info(f'Description updated for the {db_name} database')
+        # fill database
+        mmseqs_database = ['kegg', 'uniref',  'viral', 'peptidase']
+        process_functions = {i:partial(self.make_header_dict_from_mmseqs_db, 
+                                       self.config['search_databases'][i]) 
+                             for i in mmseqs_database
+                             if self.config['search_databases'][i] is not None}
+        # Use table names
+        process_functions.update({
+            'pfam': partial(self.process_pfam_descriptions,
+                                self.config.get('database_descriptions')['pfam_hmm']),
+            'dbcan': partial(self.process_dbcan_descriptions,
+                                            self.config.get('database_descriptions')['dbcan_fam_activities'], 
+                                            self.config.get('database_descriptions')['dbcan_subfam_ec']),
+            'vogdb': partial(self.process_vogdb_descriptions,
+                                         self.config.get('database_descriptions')['vog_annotations']) 
+        })
+        if select_db is not None:
+            process_functions = {i:k for i, k in process_functions.items() if i in select_db}
+
+        for i, k in process_functions.items():
+            check_db(i, k)
+            
         if update_config:  # if new description db is set then save it
             self.write_config()
 
-    def print_database_locations(self):
-        # search databases
-        print('Processed search databases')
-        print('KEGG db: %s' % self.db_locs.get('kegg'))
-        print('KOfam db: %s' % self.db_locs.get('kofam'))
-        print('KOfam KO list: %s' % self.db_locs.get('kofam_ko_list'))
-        print('UniRef db: %s' % self.db_locs.get('uniref'))
-        print('Pfam db: %s' % self.db_locs.get('pfam'))
-        print('dbCAN db: %s' % self.db_locs.get('dbcan'))
-        print('RefSeq Viral db: %s' % self.db_locs.get('viral'))
-        print('MEROPS peptidase db: %s' % self.db_locs.get('peptidase'))
-        print('VOGDB db: %s' % self.db_locs.get('vogdb'))
-        print()
-        # database descriptions used during description db population
-        print('Descriptions of search database entries')
-        print('Pfam hmm dat: %s' % self.db_description_locs.get('pfam_hmm_dat'))
-        print('dbCAN family activities: %s' % self.db_description_locs.get('dbcan_fam_activities'))
-        print('VOG annotations: %s' % self.db_description_locs.get('vog_annotations'))
-        print()
-        # description database
-        print('Description db: %s' % self.description_loc)
-        print()
-        # DRAM sheets
-        print('DRAM distillation sheets')
-        print('Genome summary form: %s' % self.dram_sheet_locs.get('genome_summary_form'))
-        print('Module step form: %s' % self.dram_sheet_locs.get('module_step_form'))
-        print('ETC module database: %s' % self.dram_sheet_locs.get('etc_module_database'))
-        print('Function heatmap form: %s' % self.dram_sheet_locs.get('function_heatmap_form'))
-        print('AMG database: %s' % self.dram_sheet_locs.get('amg_database'))
-
     def filter_db_locs(self, low_mem_mode=False, use_uniref=True, use_vogdb=True, master_list=None):
         if master_list is None:
-            dbs_to_use = self.db_locs.keys()
+            dbs_to_use = self.config['search_databases'].keys()
         else:
             dbs_to_use = master_list
         # filter out dbs for low mem mode
         if low_mem_mode:
-            if ('kofam' not in self.db_locs) or ('kofam_ko_list' not in self.db_locs):
+            if ('kofam_hmm' not in self.config.get('search_databases')) or ('kofam_ko_list' not in self.config.get('search_databases')):
                 raise ValueError('To run in low memory mode KOfam must be configured for use in DRAM')
             dbs_to_use = [i for i in dbs_to_use if i not in ('uniref', 'kegg', 'vogdb')]
         # check on uniref status
         if use_uniref:
-            if 'uniref' not in self.db_locs:
+            if 'uniref' not in self.config.get('search_databases'):
                 warnings.warn('Sequences will not be annoated against uniref as it is not configured for use in DRAM')
         else:
             dbs_to_use = [i for i in dbs_to_use if i != 'uniref']
         # check on vogdb status
         if use_vogdb:
-            if 'vogdb' not in self.db_locs:
+            if 'vogdb' not in self.config.get('search_databases'):
                 warnings.warn('Sequences will not be annoated against VOGDB as it is not configured for use in DRAM')
         else:
             dbs_to_use = [i for i in dbs_to_use if i != 'vogdb']
-        self.db_locs = {key: value for key, value in self.db_locs.items() if key in dbs_to_use}
-
-    def clear_config(self):
-        self.db_locs = {}
-        self.db_description_locs = {}
-        self.dram_sheet_locs = {}
-        self.description_loc = None
-
-
-def set_database_paths(kegg_db_loc=None, kofam_hmm_loc=None, kofam_ko_list_loc=None, uniref_db_loc=None,
-                       pfam_db_loc=None, pfam_hmm_dat=None, dbcan_db_loc=None, dbcan_fam_activities=None,
-                       viral_db_loc=None, peptidase_db_loc=None, vogdb_db_loc=None, vog_annotations=None,
-                       description_db_loc=None, genome_summary_form_loc=None, module_step_form_loc=None,
-                       etc_module_database_loc=None, function_heatmap_form_loc=None, amg_database_loc=None,
-                       clear_config=False, update_description_db=False):
-    db_handler = DatabaseHandler()
+        self.config['search_databases'] = {key: value for key, value in self.config.get('search_databases').items() if key in dbs_to_use}
+
+    def clear_config(self, write_config=False):
+        self.config = {
+                        "search_databases": {},
+                        "database_descriptions": {},
+                        "dram_sheets": {},
+                        "dram_version": current_dram_version,
+                        "description_db": None,
+                        "setup_info": {},
+                        "log_path": None
+                      }
+        if write_config:
+            self.write_config()
+
+
+def set_database_paths(clear_config=False, update_description_db=False, **kargs):
+    #TODO Add tests
+    db_handler = DatabaseHandler(None)
     if clear_config:
-        db_handler.clear_config()
-    db_handler.set_database_paths(kegg_db_loc, kofam_hmm_loc, kofam_ko_list_loc, uniref_db_loc,
-                                  pfam_db_loc, pfam_hmm_dat, dbcan_db_loc, dbcan_fam_activities,
-                                  viral_db_loc, peptidase_db_loc, vogdb_db_loc, vog_annotations,
-                                  description_db_loc, genome_summary_form_loc, module_step_form_loc,
-                                  etc_module_database_loc, function_heatmap_form_loc, amg_database_loc,
-                                  write_config=True)
+        db_handler.clear_config(write_config=True)
+    db_handler.set_database_paths(**kargs, write_config=True)
     if update_description_db:
         db_handler.populate_description_db()
 
 
 def print_database_locations(config_loc=None):
-    db_handler = DatabaseHandler(config_loc)
-    db_handler.print_database_locations()
-
-
-def populate_description_db(output_loc=None, config_loc=None):
-    db_handler = DatabaseHandler(config_loc)
-    db_handler.populate_description_db(output_loc)
+    conf = DatabaseHandler(None, config_loc)
+    # search databases
+    print('Processed search databases')
+    print('KEGG db: %s' % conf.config.get('search_databases').get('kegg'))
+    print('KOfam db: %s' % conf.config.get('search_databases').get('kofam_hmm'))
+    print('KOfam KO list: %s' % conf.config.get('search_databases').get('kofam_ko_list'))
+    print('UniRef db: %s' % conf.config.get('search_databases').get('uniref'))
+    print('Pfam db: %s' % conf.config.get('search_databases').get('pfam'))
+    print('dbCAN db: %s' % conf.config.get('search_databases').get('dbcan'))
+    print('RefSeq Viral db: %s' % conf.config.get('search_databases').get('viral'))
+    print('MEROPS peptidase db: %s' % conf.config.get('search_databases').get('peptidase'))
+    print('VOGDB db: %s' % conf.config.get('search_databases').get('vogdb'))
+    # database descriptions used during description db population
+    print('Descriptions of search database entries')
+    print('Pfam hmm dat: %s' % conf.config.get('database_descriptions').get('pfam_hmm'))
+    print('dbCAN family activities: %s' % conf.config.get('database_descriptions').get('dbcan_fam_activities'))
+    print('VOG annotations: %s' % conf.config.get('database_descriptions').get('vog_annotations'))
+    print()
+    # description database
+    print('Description db: %s' % conf.config.get('description_db'))
+    print()
+    # DRAM sheets
+    print('DRAM distillation sheets')
+    print('Genome summary form: %s' % conf.config.get('dram_sheets').get('genome_summary_form'))
+    print('Module step form: %s' % conf.config.get('dram_sheets').get('module_step_form'))
+    print('ETC module database: %s' % conf.config.get('dram_sheets').get('etc_module_database'))
+    print('Function heatmap form: %s' % conf.config.get('dram_sheets').get('function_heatmap_form'))
+    print('AMG database: %s' % conf.config.get('dram_sheets').get('amg_database'))
+
+
+def print_database_settings(config_loc=None):
+    conf = DatabaseHandler(None, config_loc)
+    print(conf.get_settings_str())
+
+
+
+def populate_description_db(output_loc=None, select_db=None,  config_loc=None):
+    db_handler = DatabaseHandler(None, config_loc)
+    db_handler.populate_description_db(output_loc, select_db)
 
 
 def export_config(output_file=None):
@@ -354,4 +483,31 @@ def export_config(output_file=None):
 
 def import_config(config_loc):
     system_config = get_config_loc()
-    copy2(config_loc, system_config)
+    db_handler = DatabaseHandler(None, config_loc)
+    with open(system_config, "w") as outfile:
+        json.dump(db_handler.config, outfile, indent=2)
+    print('Import, appears to be successfull.')
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mag_annotator/database_processing.py b/mag_annotator/database_processing.py
index 72f97091..e2e3e345 100644
--- a/mag_annotator/database_processing.py
+++ b/mag_annotator/database_processing.py
@@ -1,21 +1,135 @@
+"""
+Contains most of the backend for the DRAM_setup.py script, used to setup databases for each user.
+"""
 from os import path, mkdir
 from datetime import datetime
-from shutil import move, rmtree
+from shutil import move, rmtree, copyfile
 from glob import glob
 import gzip
-import tarfile
 from collections import defaultdict
+import logging
+import tarfile
+
 from skbio import read as read_sequence
 from skbio import write as write_sequence
 
 from mag_annotator.database_handler import DatabaseHandler
-from mag_annotator.utils import run_process, make_mmseqs_db, download_file, merge_files, remove_prefix
+from mag_annotator.utils import run_process, make_mmseqs_db, download_file, merge_files, remove_prefix, setup_logger
 
-DEFAULT_DBCAN_RELEASE = '10'
-DEFAULT_DBCAN_DATE = '07292021'
+NUMBER_OF_VIRAL_FILES = 2
+DEFAULT_DBCAN_RELEASE = '11'
+DEFAULT_DBCAN_DATE = '08062022'
 DEFAULT_UNIREF_VERSION = '90'
-
-# TODO: check if dbcan or pfam is down, raise appropriate error
+DEFAULT_VOGDB_VERSION = 'latest'
+DFLT_OUTPUT_DIR = '.'
+LOGGER = logging.getLogger("database_processing.log")
+DEFAULT_MMMSPRO_DB_NAME = 'db'
+
+
+# KOFAM_CITATION = ("Aramaki T., Blanc-Mathieu R., Endo H., Ohkubo K., Kanehisa "
+#                   "M., Goto S., Ogata H.\nKofamKOALA: KEGG ortholog assignment"
+#                   " based on profile HMM and adaptive score threshold.\nBioinf"
+#                   "ormatics. 2019 Nov 19. pii: btz859. doi: 10.1093/bioinforma"
+#                   "tics/btz859."
+#                   ) # arguably not for kofam but the closest I saw
+# VIRAL_REFSEQ_CITATION = ("Brister JR, Ako-Adjei D, Bao Y, Blinkova O. NCBI vir"
+#                          "al genomes resource. Nucleic Acids Res. 2015 Jan;43("
+#                          "Database issue):D571-7 PubMed PubMedCentral"
+#                          ) # Three options but this one is viral specific
+# KEGG_CITATION = ("Kanehisa, M., Furumichi, M., Sato, Y., Ishiguro-Watanabe, M."
+#                  ", and Tanabe, M.; KEGG: integrating viruses and cellular org"
+#                  "anisms. Nucleic Acids Res. 49, D545-D551 (2021)."
+#                  )
+# PFAM_CITATION = ("Pfam: The protein families database in 2021: J. Mistry, S. C"
+#                  "huguransky, L. Williams, M. Qureshi, G.A. Salazar, E.L.L. So"
+#                  "nnhammer, S.C.E. Tosatto, L. Paladin, S. Raj, L.J. Richardso"
+#                  "n, R.D. Finn, A. Bateman"
+#                  )
+# PEPTIDASE_CITATION = ("Rawlings, N.D., Barrett, A.J., Thomas, P.D., Huang, X.,"
+#                       " Bateman, A. & Finn, R.D. (2018) The MEROPS database of"
+#                       " proteolytic enzymes, their substrates and inhibitors i"
+#                       "n 2017 and a comparison with peptidases in the PANTHER "
+#                       "database. Nucleic Acids Res 46, D624-D632."
+#                       )
+# VOGDB_CITATION = ("Thannesberger, J., Hellinger, H. J., Klymiuk, I., Kastner, M"
+#                   ". T., Rieder, F. J., Schneider, M., ... & Steininger, C. (20"
+#                   "17). Viruses comprise an extensive pool of mobile genetic el"
+#                   "ements in eukaryote cell cultures and human clinical samples"
+#                   ". The FASEB Journal, 31(5), 1987-2000."
+#                   )
+# UNIREF_CITATION = ("Wang Y, Wang Q, Huang H, Huang W, Chen Y, McGarvey PB, Wu C"
+#                    "H, Arighi CN, UniProt Consortium. A crowdsourcing open plat"
+#                    "form for literature curation in UniProt Plos Biology. 19(12"
+#                    "):e3001464 (2021)"
+#                    )
+# DBCAN_CITATION = ("Yin Y*, Mao X*, Yang JC, Chen X, Mao F and Xu Y, dbCAN: a we"
+#                   "b resource for automated carbohydrate-active enzyme annotati"
+#                   "on, Nucleic Acids Res. 2012 Jul;40(Web Server issue):W445-51"
+#                   ) # again a citation for the tool not the db
+# DRAM_CITATION = ("M. Shaffer, M. A. Borton, B. B. McGivern, A. A. Zayed, S. L. "
+#                  "La Rosa, L. M. Solden, P. Liu, A. B. Narrowe, J. Rodríguez-Ra"
+#                  "mos, B. Bolduc et al., \"Dram for distilling microbial metabo"
+#                  "lism to automate the curation of microbiome function,\" Nucle"
+#                  "ic acids research, vol. 48, no. 16, pp. 8883–8900, 2020."
+#                  )
+
+
+KOFAM_CITATION = ("T. Aramaki, R. Blanc-Mathieu, H. Endo, K. Ohkubo, M. Kanehisa"
+                  ", S. Goto, and H. Ogata, \"Kofamkoala: Kegg ortholog assignme"
+                  "nt based on profile hmm and adaptive score threshold,\" Bioin"
+                  "formatics, vol. 36, no. 7, pp. 2251–2252, 2020."
+                  )
+VIRAL_REFSEQ_CITATION = ("J. R. Brister, D. Ako-Adjei, Y. Bao, and O. Blinkova, "
+                         "\"Ncbi viral genomes resource,\" Nucleic acids researc"
+                         "h, vol. 43, no. D1, pp. D571–D577, 2015. [3] M. Kanehi"
+                         "sa, M. Furumichi, Y. Sato, M. Ishiguro-Watanabe, and M"
+                         ". Tan-abe, \"Kegg: integrating viruses and cellular or"
+                         "ganisms,\" Nucleic acids research, vol. 49, no. D1, pp"
+                         ". D545–D551, 2021."
+                 )
+KEGG_CITATION = (" M. Kanehisa, M. Furumichi, Y. Sato, M. Ishiguro-Watanabe, and"
+                 " M. Tanabe, \"Kegg: integrating viruses and cellular organisms"
+                 ",\" Nucleic acids research, vol. 49, no. D1, pp. D545–D551, 20"
+                 "21."
+                 )
+PFAM_CITATION = ("J. Mistry, S. Chuguransky, L. Williams, M. Qureshi, G. A. Sal"
+                 "azar, E. L. Sonnhammer, S. C. Tosatto, L. Paladin, S. Raj, L."
+                 " J. Richardson et al., \"Pfam: The protein families database "
+                 "in 2021,\" Nucleic acids research, vol. 49, no. D1, pp. D412–"
+                 "D419, 2021."
+                 )
+PEPTIDASE_CITATION = ("N. D. Rawlings, A. J. Barrett, P. D. Thomas, X. Huang, A"
+                      ". Bateman, and R. D. Finn, \"The merops database of prot"
+                      "eolytic enzymes, their substrates and inhibitors in 2017"
+                      " and a comparison with peptidases in the panther databas"
+                      "e,\" Nucleic acids research, vol. 46, no. D1, pp. D624–D"
+                      "632, 2018."
+                      )
+VOGDB_CITATION = ("J. Thannesberger, H.-J. Hellinger, I. Klymiuk, M.-T. Kastner"
+                  ", F. J. Rieder, M. Schneider, S. Fister, T. Lion, K. Kosulin"
+                  ", J. Laengle et al., \"Viruses comprise an extensive pool of"
+                  " mobile genetic elements in eukaryote cell cultures and huma"
+                  "n clinical samples,\" The FASEB Journal, vol. 31, no. 5, pp."
+                  " 1987–2000, 2017."
+                  )
+UNIREF_CITATION = ("Y. Wang, Q. Wang, H. Huang, W. Huang, Y. Chen, P. B. McGarv"
+                  "ey, C. H. Wu, C. N. Arighi, and U. Consortium, \"A crowdsour"
+                  "cing open platform for literature curation in uniprot,\" PLo"
+                  "S Biology, vol. 19, no. 12, p. e3001464, 2021."
+                   )
+DBCAN_CITATION = ("Y. Yin, X. Mao, J. Yang, X. Chen, F. Mao, and Y. Xu, \"dbcan"
+                  ": a web resource for automated carbohydrate-active enzyme an"
+                  "notation,\" Nucleic acids research, vol. 40, no. W1, pp. W44"
+                  "5–W451, 2012."
+                  )
+DRAM_CITATION = ("M. Shaffer, M. A. Borton, B. B. McGivern, A. A. Zayed, S. L. "
+                 "La Rosa, L. M. Solden, P. Liu, A. B. Narrowe, J. Rodríguez-Ra"
+                 "mos, B. Bolduc et al., \"Dram for distilling microbial metabo"
+                 "lism to automate the curation of microbiome function,\" Nucle"
+                 "ic acids research, vol. 48, no. 16, pp. 8883–8900, 2020."
+                 )
+# check 
+# if dbcapfam is down, raise appropriate error
 # TODO: upgrade to pigz?
 
 
@@ -23,8 +137,57 @@ def get_iso_date():
     return datetime.today().strftime('%Y%m%d')
 
 
+def download_pfam_hmm(output_dir='.', logger=LOGGER, verbose=True):
+    pfam_hmm = path.join(output_dir, 'Pfam-A.hmm.dat.gz')
+    url = 'ftp://ftp.ebi.ac.uk/pub/databases/Pfam/current_release/Pfam-A.hmm.dat.gz'
+    url_http = 'http://ftp.ebi.ac.uk/pub/databases/Pfam/current_release/Pfam-A.hmm.dat.gz'
+    logger.debug(f"Downloading Pfam from: {url}")
+    download_file(url, pfam_hmm, logger, alt_urls=[url_http], verbose=verbose)
+    return pfam_hmm
+
+
+def download_dbcan(output_dir='.', logger=LOGGER, dbcan_hmm=None, version=DEFAULT_DBCAN_RELEASE, verbose=True):
+    dbcan_hmm = path.join(output_dir, f"dbCAN-HMMdb-V{version}.txt" )
+    if int(version) < int(DEFAULT_DBCAN_RELEASE):
+        link_path = f"http://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-HMMdb-V{version}.txt"
+    else:
+        link_path = f"http://bcb.unl.edu/dbCAN2/download/dbCAN-HMMdb-V{version}.txt"
+
+    logger.debug(f"Downloading dbCAN from: {link_path}")
+    download_file(link_path, dbcan_hmm, logger, verbose=verbose)
+    return dbcan_hmm
+
+
+def download_dbcan_fam_activities (output_dir='.', logger=LOGGER, version=DEFAULT_DBCAN_RELEASE, upload_date=DEFAULT_DBCAN_DATE, 
+                                verbose=True):
+    dbcan_fam_activities = path.join(output_dir, f'CAZyDB.{upload_date}.fam-activities.txt')
+    url = f"https://bcb.unl.edu/dbCAN2/download/Databases/V{version}/CAZyDB.{upload_date}.fam-activities.txt"
+    logger.info(f"Downloading dbCAN family activities from : {url}")
+    download_file(url, dbcan_fam_activities, logger, verbose=verbose)
+    return dbcan_fam_activities
+
+
+def download_dbcan_subfam_ec(output_dir='.', logger=LOGGER, version=DEFAULT_DBCAN_RELEASE, upload_date=DEFAULT_DBCAN_DATE, verbose=True):
+    dbcan_subfam_ec = path.join(output_dir, f"CAZyDB.{upload_date}.fam.subfam.ec.txt")
+    url = (f"https://bcb.unl.edu/dbCAN2/download/Databases/"
+                 f"V{version}/CAZyDB.{upload_date}.fam.subfam.ec.txt")
+    logger.info(f"Downloading dbCAN sub-family encumber from : {url}")
+    download_file(url, dbcan_subfam_ec, logger, verbose=verbose)
+    return dbcan_subfam_ec
+
+
+def download_kofam_hmm(output_dir='.', logger=LOGGER, verbose=False):
+    kofam_profile_tar_gz = path.join(output_dir, 'kofam_profiles.tar.gz')
+    url = 'ftp://ftp.genome.jp/pub/db/kofam/profiles.tar.gz'  
+    url_http = 'https://www.genome.jp/ftp/db/kofam/profiles.tar.gz'
+    download_file(url, kofam_profile_tar_gz, logger, alt_urls=[url_http], verbose=verbose)
+    return kofam_profile_tar_gz
+
 def generate_modified_kegg_fasta(kegg_fasta, gene_ko_link_loc=None):
-    """Takes kegg fasta file and gene ko link file, adds kos not already in headers to headers"""
+    """
+    Takes kegg fasta file and gene ko link file, adds kos not already in headers to headers
+    Whish I knew about this, oh well I may split this out.
+    """
     genes_ko_dict = defaultdict(list)
     if gene_ko_link_loc is not None:
         if gene_ko_link_loc.endswith('.gz'):
@@ -43,7 +206,9 @@ def generate_modified_kegg_fasta(kegg_fasta, gene_ko_link_loc=None):
         yield seq
 
 
-def process_kegg_db(output_dir, kegg_loc, gene_ko_link_loc=None, download_date=None, threads=10, verbose=True):
+
+def process_kegg(kegg_loc, output_dir, logger, gene_ko_link_loc=None, download_date=None, 
+                    threads=10, verbose=True):
     if download_date is None:
         download_date = get_iso_date()
     if gene_ko_link_loc is not None:
@@ -55,340 +220,427 @@ def process_kegg_db(output_dir, kegg_loc, gene_ko_link_loc=None, download_date=N
         kegg_mod_loc = kegg_loc
     # make mmseqsdb from modified kegg fasta
     kegg_mmseqs_db = path.join(output_dir, 'kegg.%s.mmsdb' % download_date)
-    make_mmseqs_db(kegg_mod_loc, kegg_mmseqs_db, create_index=True, threads=threads, verbose=verbose)
-    return kegg_mmseqs_db
+    make_mmseqs_db(kegg_mod_loc, kegg_mmseqs_db, logger, create_index=True, threads=threads, verbose=verbose)
+    LOGGER.info('KEGG database processed')
+    return {'kegg': kegg_mmseqs_db}
 
 
-def download_and_process_kofam_hmms(kofam_profile_tar_gz=None, output_dir='.', verbose=False):
-    if kofam_profile_tar_gz is None:
-        kofam_profile_tar_gz = path.join(output_dir, 'kofam_profiles.tar.gz')
-        download_file('ftp://ftp.genome.jp/pub/db/kofam/profiles.tar.gz', kofam_profile_tar_gz, verbose=verbose)
+def process_kofam_hmm(kofam_profile_tar_gz, output_dir=DFLT_OUTPUT_DIR, logger=LOGGER, threads=1, verbose=False):
     kofam_profiles = path.join(output_dir, 'kofam_profiles')
     mkdir(kofam_profiles)
-    run_process(['tar', '-xzf', kofam_profile_tar_gz, '-C', kofam_profiles], verbose=verbose)
+    run_process(['tar', '-xzf', kofam_profile_tar_gz, '-C', kofam_profiles], logger, verbose=verbose)
     merged_kofam_profiles = path.join(output_dir, 'kofam_profiles.hmm')
     merge_files(glob(path.join(kofam_profiles, 'profiles', '*.hmm')), merged_kofam_profiles)
-    run_process(['hmmpress', '-f', merged_kofam_profiles], verbose=verbose)
-    return merged_kofam_profiles
+    run_process(['hmmpress', '-f', merged_kofam_profiles], logger, verbose=verbose)
+    LOGGER.info('KOfam database processed')
+    return {'kofam_hmm': merged_kofam_profiles}
+
+
+def download_kofam_ko_list(output_dir='.', logger=LOGGER, verbose=False):
+    kofam_ko_list_gz = path.join(output_dir, 'kofam_ko_list.tsv.gz')
+    url = 'ftp://ftp.genome.jp/pub/db/kofam/ko_list.gz'
+    url_http = 'https://www.genome.jp/ftp/db/kofam/ko_list.gz'
+    download_file(url, kofam_ko_list_gz, logger, alt_urls=[url_http], verbose=verbose)
+    return kofam_ko_list_gz
+
+
+def download_pfam(output_dir='.', logger=LOGGER, verbose=True):
+    pfam_full_zipped = path.join(output_dir, 'Pfam-A.full.gz')
+    url = 'ftp://ftp.ebi.ac.uk/pub/databases/Pfam/current_release/Pfam-A.full.gz'
+    http_url = 'http://ftp.ebi.ac.uk/pub/databases/Pfam/current_release/Pfam-A.full.gz'
+    download_file(url, pfam_full_zipped, logger, alt_urls=[http_url], verbose=verbose)
+    return pfam_full_zipped
 
 
-def download_and_process_kofam_ko_list(kofam_ko_list_gz=None, output_dir='.', verbose=False):
-    if kofam_ko_list_gz is None:
-        kofam_ko_list_gz = path.join(output_dir, 'kofam_ko_list.tsv.gz')
-        download_file('ftp://ftp.genome.jp/pub/db/kofam/ko_list.gz', kofam_ko_list_gz, verbose=verbose)
+def download_viral(output_dir='.', logger=LOGGER, viral_files=NUMBER_OF_VIRAL_FILES, verbose=True):
+    """Can only download newest version"""
+    # download all of the viral protein files, need to know the number of files
+    # TODO: Make it so that you don't need to know number of viral files in refseq viral
+    faa_base_name = 'viral.%s.protein.faa.gz'
+    viral_faa_glob = path.join(output_dir, faa_base_name % '*')
+    for number in range(viral_files):
+        number += 1
+        url = 'ftp://ftp.ncbi.nlm.nih.gov/refseq/release/viral/viral.%s.protein.faa.gz' % number
+        url_http = 'https://ftp.ncbi.nlm.nih.gov/refseq/release/viral/viral.%s.protein.faa.gz' % number
+        output_name= path.join(output_dir, faa_base_name % number)
+        download_file(url, output_name, logger, alt_urls=[url_http], verbose=verbose)
+    # then merge files from above
+    merged_viral_faas = path.join(output_dir, 'viral.merged.protein.faa.gz')
+    run_process(['cat %s > %s' % (' '.join(glob(viral_faa_glob)), merged_viral_faas)], logger, shell=True)
+    return merged_viral_faas
+
+
+def download_uniref(output_dir='.', logger=LOGGER, version=DEFAULT_UNIREF_VERSION, 
+                    threads=10, verbose=True):
+    uniref_fasta_zipped = path.join(output_dir, 'uniref%s.fasta.gz' % version)
+    url = 'ftp://ftp.uniprot.org/pub/databases/uniprot/uniref/uniref%s/uniref%s.fasta.gz' % \
+          (version, version)
+    url_http = 'https://ftp.uniprot.org/pub/databases/uniprot/uniref/uniref%s/uniref%s.fasta.gz' % \
+                 (version, version)
+    download_file(url, uniref_fasta_zipped, logger, alt_urls=[url_http], verbose=verbose)
+    return uniref_fasta_zipped
+
+
+def download_peptidase(output_dir='.', logger=LOGGER, verbose=True):
+    save_name = path.join(output_dir, 'merops_peptidases_nr.faa')
+    url = 'ftp://ftp.ebi.ac.uk/pub/databases/merops/current_release/pepunit.lib'
+    url_http = 'https://ftp.ebi.ac.uk/pub/databases/merops/current_release/pepunit.lib'
+    download_file(url, save_name, logger, alt_urls=[url_http], verbose=verbose)
+    return save_name
+
+def download_vogdb(output_dir='.', logger=LOGGER, version=DEFAULT_VOGDB_VERSION, verbose=True):
+    vog_hmm_targz = path.join(output_dir, 'vog.hmm.tar.gz')
+    vogdb_url = f'http://fileshare.csb.univie.ac.at/vog/{version}/vog.hmm.tar.gz'
+    download_file(vogdb_url, vog_hmm_targz, logger, verbose=verbose)
+    return vog_hmm_targz
+
+
+def process_kofam_ko_list(kofam_ko_list_gz, output_dir='.', logger=LOGGER, threads=1, verbose=False):
     # TODO: fix this so that it is gunzipped to the path
     kofam_ko_list = path.join(output_dir, 'kofam_ko_list.tsv')
-    run_process(['gunzip', kofam_ko_list_gz], verbose=verbose)
-    return kofam_ko_list
+    run_process(['gunzip', '-c', kofam_ko_list_gz], logger, save_output=kofam_ko_list, verbose=verbose)
+    LOGGER.info('KOfam ko list processed')
+    return {'kofam_ko_list': kofam_ko_list}
 
 
-def download_and_process_uniref(uniref_fasta_zipped=None, output_dir='.', uniref_version=DEFAULT_UNIREF_VERSION, threads=10,
-                                verbose=True):
-    """"""
-    if uniref_fasta_zipped is None:  # download database if not provided
-        uniref_fasta_zipped = path.join(output_dir, 'uniref%s.fasta.gz' % uniref_version)
-        uniref_url = 'https://ftp.uniprot.org/pub/databases/uniprot/uniref/uniref%s/uniref%s.fasta.gz' % \
-                     (uniref_version, uniref_version)
-        download_file(uniref_url, uniref_fasta_zipped, verbose=verbose)
-    uniref_mmseqs_db = path.join(output_dir, 'uniref%s.%s.mmsdb' % (uniref_version, get_iso_date()))
-    make_mmseqs_db(uniref_fasta_zipped, uniref_mmseqs_db, create_index=True, threads=threads, verbose=verbose)
-    return uniref_mmseqs_db
-
-
-def process_mmspro(full_alignment, output_dir, db_name='db', threads=10, verbose=True):
+def process_uniref(uniref_fasta_zipped, output_dir='.', logger=LOGGER, 
+                   version=DEFAULT_UNIREF_VERSION, threads=10,
+                   verbose=True):
+    uniref_mmseqs_db = path.join(output_dir, 'uniref%s.%s.mmsdb' % (version, get_iso_date()))
+    make_mmseqs_db(uniref_fasta_zipped, uniref_mmseqs_db, logger, create_index=True, threads=threads, verbose=verbose)
+    LOGGER.info('UniRef database processed')
+    return {'uniref': uniref_mmseqs_db}
+
+
+def process_mmspro(full_alignment, output_dir, logger=LOGGER, db_name=DEFAULT_MMMSPRO_DB_NAME, threads=10, verbose=True):
     mmseqs_msa = path.join(output_dir, '%s.mmsmsa' % db_name)
-    run_process(['mmseqs', 'convertmsa', full_alignment, mmseqs_msa], verbose=verbose)
+    run_process(['mmseqs', 'convertmsa', full_alignment, mmseqs_msa], logger, verbose=verbose)
     mmseqs_profile = path.join(output_dir, '%s.mmspro' % db_name)
-    run_process(['mmseqs', 'msa2profile', mmseqs_msa, mmseqs_profile, '--match-mode', '1', '--threads', str(threads)],
+    run_process(['mmseqs', 'msa2profile', mmseqs_msa, mmseqs_profile, '--match-mode', '1', '--threads', str(threads)], 
+                logger,
                 verbose=verbose)
     tmp_dir = path.join(output_dir, 'tmp')
-    run_process(['mmseqs', 'createindex', mmseqs_profile, tmp_dir, '-k', '5', '-s', '7', '--threads', str(threads)],
+    run_process(['mmseqs', 'createindex', mmseqs_profile, tmp_dir, '-k', '5', '-s', '7', '--threads', str(threads)], 
+                logger,
                 verbose=verbose)
     return mmseqs_profile
 
 
-def download_and_process_pfam(pfam_full_zipped=None, output_dir='.', threads=10, verbose=True):
-    if pfam_full_zipped is None:  # download database if not provided
-        pfam_full_zipped = path.join(output_dir, 'Pfam-A.full.gz')
-        download_file('ftp://ftp.ebi.ac.uk/pub/databases/Pfam/current_release/Pfam-A.full.gz', pfam_full_zipped,
-                      verbose=verbose)
-    pfam_profile = process_mmspro(pfam_full_zipped, output_dir, 'pfam', threads, verbose)
-    return pfam_profile
-
-
-def download_pfam_descriptions(output_dir='.', verbose=True):
-    pfam_hmm_dat = path.join(output_dir, 'Pfam-A.hmm.dat.gz')
-    download_file('ftp://ftp.ebi.ac.uk/pub/databases/Pfam/current_release/Pfam-A.hmm.dat.gz', pfam_hmm_dat,
-                  verbose=verbose)
-    return pfam_hmm_dat
+def process_pfam(pfam_full_zipped, output_dir='.', logger=LOGGER, threads=10, verbose=True):
+    pfam_profile = process_mmspro(pfam_full_zipped, output_dir, logger, 'pfam', threads, verbose)
+    LOGGER.info('PFAM database processed')
+    return {'pfam': pfam_profile}
 
 
-def download_dbcan(dbcan_hmm=None, output_dir='.', dbcan_release=DEFAULT_DBCAN_RELEASE, verbose=True):
-    dbcan_hmm = path.join(output_dir, f"dbCAN-HMMdb-V{dbcan_release}.txt" )
-    if int(dbcan_release) < int(DEFAULT_DBCAN_RELEASE):
-        link_path = f"http://bcb.unl.edu/dbCAN2/download/Databases/dbCAN-HMMdb-V{dbcan_release}.txt"
-    else:
-        link_path = f"http://bcb.unl.edu/dbCAN2/download/dbCAN-HMMdb-V{dbcan_release}.txt"
-
-    print(f"Downloading dbCAN from: {link_path}")
-    download_file(link_path, dbcan_hmm, verbose=verbose)
-    return dbcan_hmm
+def process_dbcan(input, output_dir, logger=LOGGER, verbose=True, threads=1):
+    output = path.join(output_dir, path.basename(input))
+    move(input, output)
+    run_process(['hmmpress', '-f', output], logger, verbose=verbose)
+    LOGGER.info('dbCAN database processed')
+    return {'dbcan': output}
 
 
-def process_dbcan(dbcan_hmm, verbose=True):
-    run_process(['hmmpress', '-f', dbcan_hmm], verbose=verbose)
-    return dbcan_hmm
-
-
-def download_dbcan_descriptions(output_dir='.', dbcan_release=DEFAULT_DBCAN_RELEASE, upload_date=DEFAULT_DBCAN_DATE, verbose=True):
-    dbcan_fam_activities = path.join(output_dir, 'CAZyDB.%s.fam-activities.txt' % upload_date)
-    link_path = f"https://bcb.unl.edu/dbCAN2/download/Databases/V{dbcan_release}/CAZyDB.{upload_date}.fam-activities.txt"
-    print(f"Downloading dbCAN family activities from : {link_path}")
-    download_file(link_path, dbcan_fam_activities, verbose=verbose)
-    return dbcan_fam_activities
-
-
-def download_and_process_viral_refseq(merged_viral_faas=None, output_dir='.', viral_files=2, threads=10, verbose=True):
-    """Can only download newest version"""
-    # download all of the viral protein files, need to know the number of files
-    # TODO: Make it so that you don't need to know number of viral files in refseq viral
-
-    if merged_viral_faas is None:  # download database if not provided
-        faa_base_name = 'viral.%s.protein.faa.gz'
-        viral_faa_glob = path.join(output_dir, faa_base_name % '*')
-        for number in range(viral_files):
-            number += 1
-            refseq_url = 'ftp://ftp.ncbi.nlm.nih.gov/refseq/release/viral/viral.%s.protein.faa.gz' % number
-            refseq_faa = path.join(output_dir, faa_base_name % number)
-            download_file(refseq_url, refseq_faa, verbose=verbose)
-
-        # then merge files from above
-        merged_viral_faas = path.join(output_dir, 'viral.merged.protein.faa.gz')
-        run_process(['cat %s > %s' % (' '.join(glob(viral_faa_glob)), merged_viral_faas)], shell=True)
-
-    # make mmseqs database
+def process_viral(merged_viral_faas, output_dir='.', logger=LOGGER, viral_files=NUMBER_OF_VIRAL_FILES, threads=10, verbose=True):
     refseq_viral_mmseqs_db = path.join(output_dir, 'refseq_viral.%s.mmsdb' % get_iso_date())
-    make_mmseqs_db(merged_viral_faas, refseq_viral_mmseqs_db, create_index=True, threads=threads, verbose=verbose)
-    return refseq_viral_mmseqs_db
+    make_mmseqs_db(merged_viral_faas, refseq_viral_mmseqs_db, logger, create_index=True, threads=threads, verbose=verbose)
+    LOGGER.info('RefSeq viral database processed')
+    return {'viral': refseq_viral_mmseqs_db}
 
 
-def download_and_process_merops_peptidases(peptidase_faa=None, output_dir='.', threads=10, verbose=True):
-    if peptidase_faa is None:  # download database if not provided
-        peptidase_faa = path.join(output_dir, 'merops_peptidases_nr.faa')
-        merops_url = 'ftp://ftp.ebi.ac.uk/pub/databases/merops/current_release/pepunit.lib'
-        download_file(merops_url, peptidase_faa, verbose=verbose)
+
+def process_peptidase(peptidase_faa, output_dir='.', logger=LOGGER, threads=10, verbose=True):
     peptidase_mmseqs_db = path.join(output_dir, 'peptidases.%s.mmsdb' % get_iso_date())
-    make_mmseqs_db(peptidase_faa, peptidase_mmseqs_db, create_index=True, threads=threads, verbose=verbose)
-    return peptidase_mmseqs_db
+    make_mmseqs_db(peptidase_faa, peptidase_mmseqs_db, logger, create_index=True, threads=threads, verbose=verbose)
+    LOGGER.info('MEROPS database processed')
+    return {'peptidase': peptidase_mmseqs_db}
 
 
-def download_and_process_vogdb(vog_hmm_targz=None, output_dir='.', vogdb_release='latest', verbose=True):
-    if vog_hmm_targz is None:
-        vog_hmm_targz = path.join(output_dir, 'vog.hmm.tar.gz')
-        vogdb_url = 'http://fileshare.csb.univie.ac.at/vog/%s/vog.hmm.tar.gz' % vogdb_release
-        download_file(vogdb_url, vog_hmm_targz, verbose=verbose)
+def process_vogdb(vog_hmm_targz, output_dir='.', logger=LOGGER, version=DEFAULT_VOGDB_VERSION, threads=1, verbose=True):
     hmm_dir = path.join(output_dir, 'vogdb_hmms')
     mkdir(hmm_dir)
     vogdb_targz = tarfile.open(vog_hmm_targz)
     vogdb_targz.extractall(hmm_dir)
-    vog_hmms = path.join(output_dir, 'vog_%s_hmms.txt' % vogdb_release)
+    vog_hmms = path.join(output_dir, f'vog_{version}_hmms.txt')
     merge_files(glob(path.join(hmm_dir, 'VOG*.hmm')), vog_hmms)
-    run_process(['hmmpress', '-f', vog_hmms], verbose=verbose)
-    return vog_hmms
+    run_process(['hmmpress', '-f', vog_hmms], logger, verbose=verbose) 
+    LOGGER.info('VOGdb database processed')
+    return {'vogdb': vog_hmms}
 
 
-def download_vog_annotations(output_dir, vogdb_version='latest', verbose=True):
-    vog_annotations = path.join(output_dir, 'vog_annotations_%s.tsv.gz' % vogdb_version)
-    download_file('http://fileshare.csb.univie.ac.at/vog/%s/vog.annotations.tsv.gz' % vogdb_version,
-                  vog_annotations, verbose=verbose)
+def download_vog_annotations(output_dir, logger=LOGGER, version=DEFAULT_VOGDB_VERSION, verbose=True):
+    vog_annotations = path.join(output_dir, 'vog_annotations_%s.tsv.gz' % version)
+    download_file('http://fileshare.csb.univie.ac.at/vog/%s/vog.annotations.tsv.gz' % version,
+                  vog_annotations, logger, verbose=verbose)
     return vog_annotations
 
 
-def download_and_process_genome_summary_form(output_dir, branch='master', verbose=True):
+def download_genome_summary_form(output_dir, logger=LOGGER, branch='master', verbose=True):
     genome_summary_form = path.join(output_dir, 'genome_summary_form.%s.tsv' % get_iso_date())
-    download_file('https://raw.githubusercontent.com/shafferm/DRAM/%s/data/genome_summary_form.tsv' % branch,
-                  genome_summary_form, verbose=verbose)
+    download_file('https://raw.githubusercontent.com/WrightonLabCSU/DRAM/%s/data/genome_summary_form.tsv' % branch,
+                  genome_summary_form, logger, verbose=verbose)
     return genome_summary_form
 
 
-def download_and_process_module_step_form(output_dir, branch='master', verbose=True):
+def download_module_step_form(output_dir, logger=LOGGER, branch='master', verbose=True):
     function_heatmap_form = path.join(output_dir, 'module_step_form.%s.tsv' % get_iso_date())
-    download_file('https://raw.githubusercontent.com/shafferm/DRAM/%s/data/module_step_form.tsv' % branch,
-                  function_heatmap_form, verbose=verbose)
+    download_file('https://raw.githubusercontent.com/WrightonLabCSU/DRAM/%s/data/module_step_form.tsv' % branch,
+                  function_heatmap_form, logger, verbose=verbose)
     return function_heatmap_form
 
 
-def download_and_process_etc_module_database(output_dir, branch='master', verbose=True):
+def download_etc_module_database(output_dir, logger=LOGGER, branch='master', verbose=True):
     etc_module_database = path.join(output_dir, 'etc_mdoule_database.%s.tsv' % get_iso_date())
-    download_file('https://raw.githubusercontent.com/shafferm/DRAM/%s/data/etc_module_database.tsv' % branch,
-                  etc_module_database, verbose=verbose)
+    download_file('https://raw.githubusercontent.com/WrightonLabCSU/DRAM/%s/data/etc_module_database.tsv' % branch,
+                  etc_module_database, logger, verbose=verbose)
     return etc_module_database
 
 
-def download_and_process_function_heatmap_form(output_dir, branch='master', verbose=True):
+def download_function_heatmap_form(output_dir, logger=LOGGER, branch='master', verbose=True):
     function_heatmap_form = path.join(output_dir, 'function_heatmap_form.%s.tsv' % get_iso_date())
-    download_file('https://raw.githubusercontent.com/shafferm/DRAM/%s/data/function_heatmap_form.tsv' % branch,
-                  function_heatmap_form, verbose=verbose)
+    download_file('https://raw.githubusercontent.com/WrightonLabCSU/DRAM/%s/data/function_heatmap_form.tsv' % branch,
+                  function_heatmap_form, logger, verbose=verbose)
     return function_heatmap_form
 
 
-def download_and_process_amg_database(output_dir, branch='master', verbose=True):
+def download_amg_database(output_dir, logger=LOGGER, branch='master', verbose=True):
     amg_database = path.join(output_dir, 'amg_database.%s.tsv' % get_iso_date())
-    download_file('https://raw.githubusercontent.com/shafferm/DRAM/%s/data/amg_database.tsv' % branch,
-                  amg_database, verbose=verbose)
+    download_file('https://raw.githubusercontent.com/WrightonLabCSU/DRAM/%s/data/amg_database.tsv' % branch, 
+                  amg_database, logger, verbose=verbose,)
     return amg_database
 
 
-def check_file_exists(db_loc):
-    if db_loc is None:
-        return True
-    elif path.isfile(db_loc):
-        return True
-    else:
-        raise ValueError("Database location does not exist: %s" % db_loc)
-
-
-def prepare_databases(output_dir, kegg_loc=None, gene_ko_link_loc=None, kofam_hmm_loc=None, kofam_ko_list_loc=None,
-                      kegg_download_date=None, uniref_loc=None, uniref_version=DEFAULT_UNIREF_VERSION, pfam_loc=None, pfam_hmm_dat=None,
-                      dbcan_loc=None, dbcan_version=DEFAULT_DBCAN_RELEASE, dbcan_fam_activities=None, dbcan_date=DEFAULT_DBCAN_DATE,
-                      viral_loc=None, peptidase_loc=None, vogdb_loc=None, vogdb_version='latest', vog_annotations=None,
-                      genome_summary_form_loc=None, module_step_form_loc=None, etc_module_database_loc=None,
-                      function_heatmap_form_loc=None, amg_database_loc=None, skip_uniref=False,
-                      keep_database_files=False, branch='master', threads=10, verbose=True):
-    start_time = datetime.now()
-    print('%s: Database preparation started' % str(datetime.now()))
-
-    # check inputs
-    if skip_uniref and uniref_loc is not None:
-        raise ValueError('Cannot skip UniRef processing and provide a location of UniRef. Skipping UniRef will cause '
-                         'provided UniRef file to not be used.')
-
-    # check that all given files exist
-    check_file_exists(kegg_loc)
-    check_file_exists(gene_ko_link_loc)
-    check_file_exists(kofam_hmm_loc)
-    check_file_exists(kofam_ko_list_loc)
-    check_file_exists(uniref_loc)
-    check_file_exists(pfam_loc)
-    check_file_exists(pfam_hmm_dat)
-    check_file_exists(dbcan_loc)
-    check_file_exists(dbcan_fam_activities)
-    check_file_exists(vogdb_loc)
-    check_file_exists(viral_loc)
-    check_file_exists(peptidase_loc)
-    check_file_exists(genome_summary_form_loc)
-    check_file_exists(module_step_form_loc)
-    check_file_exists(function_heatmap_form_loc)
-    check_file_exists(amg_database_loc)
-
-    # setup
+def check_file_exists(*paths):
+    for i in paths:
+        if i is None:
+            continue
+        elif path.isfile(i):
+            continue
+        else:
+            raise ValueError(f"Database location does not exist: {i}")
+
+
+def prepare_databases(output_dir, loggpath=None, kegg_loc=None, gene_ko_link_loc=None, kofam_hmm_loc=None,
+                      kofam_ko_list_loc=None, kegg_download_date=None, uniref_loc=None,
+                      uniref_version=DEFAULT_UNIREF_VERSION, pfam_loc=None, pfam_hmm_loc=None,
+                      dbcan_loc=None, dbcan_fam_activities:str=None, dbcan_subfam_ec:str=None, dbcan_version=DEFAULT_DBCAN_RELEASE,
+                      dbcan_date=DEFAULT_DBCAN_DATE, viral_loc=None, peptidase_loc=None,
+                      vogdb_loc=None, vogdb_version=DEFAULT_VOGDB_VERSION, vog_annotations=None,
+                      genome_summary_form_loc=None, module_step_form_loc=None,
+                      etc_module_database_loc=None, function_heatmap_form_loc=None,
+                      amg_database_loc=None,
+                      number_of_viral_files=NUMBER_OF_VIRAL_FILES,
+                      skip_uniref=False, keep_database_files=False,
+                      branch='master', threads=10, verbose=True, select_db=None, clear_config=False):
+
+
+    dram_settings = {
+        'kegg':                  {'name': 'KEGG db', 
+                                  'description_db_updated': 'Unknown, or Never', 
+                                  'citation': KEGG_CITATION},
+        'gene_ko_link':          {'name': 'KEGG Gene KO link', 'citation': KEGG_CITATION},
+        "kofam_hmm":             {'name': 'KOfam db', 'citation': KOFAM_CITATION},
+        "kofam_ko_list":         {'name': 'KOfam KO list', 'citation': KOFAM_CITATION},
+        'uniref':                {'name': 'UniRef db', 
+                                  'description_db_updated': 'Unknown, or Never', 
+                                  'citation': UNIREF_CITATION},
+        'pfam':                  {'name': 'Pfam db', 'citation': PFAM_CITATION},
+        "pfam_hmm":          {'name': 'Pfam hmm dat', 
+                                  'description_db_updated': 'Unknown, or Never', 
+                                  'citation': PFAM_CITATION},
+        "dbcan":                 {'name': 'dbCAN db', 'citation': DBCAN_CITATION},
+        "dbcan_fam_activities":  {'name': 'dbCAN family activities', 'citation': DBCAN_CITATION}, 
+        "dbcan_subfam_ec":       {'name': 'dbCAN subfamily EC numbers', 'citation': DBCAN_CITATION},
+        "vogdb":                 {'name': 'VOGDB db', 'citation': VOGDB_CITATION},
+        "vog_annotations":       {'name': 'VOG annotations', 
+                                  'description_db_updated': 'Unknown, or Never', 
+                                  'citation': VOGDB_CITATION},
+        "viral":          {'name': 'RefSeq Viral db', 
+                                  'description_db_updated': 'Unknown, or Never', 
+                                  'citation': VIRAL_REFSEQ_CITATION},
+        "peptidase":             {'name': 'MEROPS peptidase db', 
+                                  'description_db_updated': 'Unknown, or Never', 
+                                  'citation': PEPTIDASE_CITATION}, 
+        "genome_summary_form":   {'name': 'Genome summary form'},
+        "module_step_form":      {'name': 'Module step form'},
+        "function_heatmap_form": {'name': 'Function heatmap form'},
+        "amg_database":          {'name': 'AMG database'},
+        "etc_module_database":   {'name': 'ETC module database'},
+    }
+    database_settings= {
+        'kegg':                  {},
+        "gene_ko_link":          {},
+        "kofam_hmm":             {},
+        "kofam_ko_list":         {},
+        'uniref':                {'version': uniref_version},
+        'pfam':                  {},
+        "pfam_hmm":          {},
+        "dbcan":                 {'version': dbcan_version},
+        "dbcan_fam_activities":  {'version': dbcan_version, 'upload_date': dbcan_date}, 
+        "dbcan_subfam_ec":       {'version': dbcan_version, 'upload_date': dbcan_date},
+        "vogdb":                 {'version': vogdb_version},
+        "vog_annotations":       {'version': vogdb_version},
+        "viral":                 {},
+        "peptidase":             {}, 
+        "genome_summary_form":   {"branch": branch},
+        "module_step_form":      {"branch": branch},
+        "function_heatmap_form": {"branch": branch},
+        "amg_database":          {"branch": branch},
+        "etc_module_database":   {"branch": branch},
+    }
+    process_settings = {
+        'kegg': {},
+        "gene_ko_link": {},
+        "kofam_hmm": {},
+        "kofam_ko_list": {},
+        'uniref': {"version": uniref_version},
+        'pfam': {},
+        "pfam_hmm": {},
+        "dbcan": {},
+        "dbcan_fam_activities": {}, 
+        "dbcan_subfam_ec": {},
+        "vogdb": {},
+        "vog_annotations": {},
+        "viral": {'viral_files': number_of_viral_files},
+        "peptidase": {}, 
+        "genome_summary_form": {},
+        "module_step_form": {},
+        "function_heatmap_form": {},
+        "amg_database": {},
+        "etc_module_database": {},
+    }
+
+    # setup temp, logging, and db_handler
     if not path.isdir(output_dir):
         mkdir(output_dir)
     temporary = path.join(output_dir, 'database_files')
     mkdir(temporary)
+    main_log = path.join(output_dir, 'database_processing.log')
+    setup_logger(LOGGER, *[(main_log, loggpath) if loggpath is not None else main_log])
+    db_handler = DatabaseHandler(logger=LOGGER)
+    if clear_config or select_db is None:
+        db_handler.clear_config()
+
+    db_handler.config['log_path'] = main_log
+    db_handler.write_config()
+    LOGGER.info('Starting the process of downloading data')
+
+    if skip_uniref:
+        LOGGER.info('Skipping UniRef')
+        del database_settings['uniref']
+    
+    
+    locs = {i.removesuffix('_loc'):j for i, j in locals().items() if i.endswith('_loc') and j is not None}
+    download_functions = {i[9:]:j for i,j in globals().items() if callable(j) and i.startswith('download_')}
+    process_functions = {i[8:]:j for i,j in globals().items() if callable(j) and i.startswith('process_')}
+    functions = {i:j for i,j in globals().items() if callable(j) and i.startswith('download_')}
+
+    # Check any specified paths exist
+    missing_user_inputs = [i for i in locs if not path.exists(i)]
+    if len(missing_user_inputs) > 1:
+        raise ValueError(f"The fallowing user provided paths don't seem to exist: {missing_user_inputs}")
+
+    un_obtainable = [i for i in database_settings if i not in locs and i not in download_functions]
+
+    for i in un_obtainable:
+        LOGGER.info(f"The {i}_loc argument was not used to specify a downloaded {i} file, and dram can not"
+                     " download it its self. So it is assumed that the user wants to set up DRAM without it")
+        del database_settings[i]
 
-    # Download DBs
-    if dbcan_fam_activities is None:
-        dbcan_fam_activities = download_dbcan_descriptions(
-            output_dir=output_dir, dbcan_release=dbcan_version,
-            upload_date=dbcan_date, verbose=verbose)
-    if pfam_hmm_dat is None:
-        pfam_hmm_dat = download_pfam_descriptions(output_dir, verbose=verbose)
-    if dbcan_loc is None:
-        dbcan_loc = download_dbcan(temporary, dbcan_release=dbcan_version, verbose=verbose)
 
-    # Process databases
-    output_dbs = dict()
-
-    output_dbs['dbcan_db_loc'] = process_dbcan(dbcan_loc, verbose=verbose)
-    print('%s: dbCAN database processed' % str(datetime.now() - start_time))
-
-    if kegg_loc is not None:
-        output_dbs['kegg_db_loc'] = process_kegg_db(temporary, kegg_loc, gene_ko_link_loc, kegg_download_date, threads,
-                                                    verbose)
-        print('%s: KEGG database processed' % str(datetime.now() - start_time))
-    if not skip_uniref:
-        output_dbs['uniref_db_loc'] = download_and_process_uniref(uniref_loc, temporary, uniref_version=uniref_version,
-                                                                  threads=threads, verbose=verbose)
-        print('%s: UniRef database processed' % str(datetime.now() - start_time))
-    output_dbs['pfam_db_loc'] = download_and_process_pfam(pfam_loc, temporary,
-                                                          threads=threads, verbose=verbose)
-    print('%s: PFAM database processed' % str(datetime.now() - start_time))
-    output_dbs['viral_db_loc'] = download_and_process_viral_refseq(viral_loc, temporary, threads=threads,
-                                                                   verbose=verbose)
-    print('%s: RefSeq viral database processed' % str(datetime.now() - start_time))
-    output_dbs['peptidase_db_loc'] = download_and_process_merops_peptidases(peptidase_loc, temporary, threads=threads,
-                                                                            verbose=verbose)
-    print('%s: MEROPS database processed' % str(datetime.now() - start_time))
-    output_dbs['vogdb_db_loc'] = download_and_process_vogdb(vogdb_loc, temporary, vogdb_release=vogdb_version,
-                                                            verbose=verbose)
-    print('%s: VOGdb database processed' % str(datetime.now() - start_time))
-    output_dbs['kofam_hmm_loc'] = download_and_process_kofam_hmms(kofam_hmm_loc, temporary, verbose=verbose)
-    print('%s: KOfam database processed' % str(datetime.now() - start_time))
-    output_dbs['kofam_ko_list_loc'] = download_and_process_kofam_ko_list(kofam_ko_list_loc, temporary, verbose=verbose)
-    print('%s: KOfam ko list processed' % str(datetime.now() - start_time))
-
-    # get pfam, dbcan and vogdb descriptions
-    output_dbs['pfam_hmm_dat'] = pfam_hmm_dat
-    print('%s: PFAM hmm dat processed' % str(datetime.now() - start_time))
-    output_dbs['dbcan_fam_activities'] = dbcan_fam_activities
-    print('%s: dbCAN fam activities processed' % str(datetime.now() - start_time))
-    if vog_annotations is None:
-        vog_annotations = download_vog_annotations(output_dir, vogdb_version, verbose=verbose)
-    output_dbs['vog_annotations'] = vog_annotations
-    print('%s: VOGdb annotations processed' % str(datetime.now() - start_time))
-
-    # add genome summary form and function heatmap form
-    if genome_summary_form_loc is None:
-        output_dbs['genome_summary_form_loc'] = download_and_process_genome_summary_form(temporary, branch, verbose)
-    else:
-        output_dbs['genome_summary_form_loc'] = genome_summary_form_loc
-    if module_step_form_loc is None:
-        output_dbs['module_step_form_loc'] = download_and_process_module_step_form(temporary, branch, verbose)
-    else:
-        output_dbs['module_step_form_loc'] = module_step_form_loc
-    if etc_module_database_loc is None:
-        output_dbs['etc_module_database_loc'] = download_and_process_etc_module_database(temporary, branch, verbose)
-    else:
-        output_dbs['etc_module_database_loc'] = etc_module_database_loc
-    if function_heatmap_form_loc is None:
-        output_dbs['function_heatmap_form_loc'] = download_and_process_function_heatmap_form(temporary, branch, verbose)
-    else:
-        output_dbs['function_heatmap_form_loc'] = function_heatmap_form_loc
-    if amg_database_loc is None:
-        output_dbs['amg_database_loc'] = download_and_process_amg_database(temporary, branch, verbose)
-    else:
-        output_dbs['amg_database_loc'] = amg_database_loc
-    print('%s: DRAM databases and forms downloaded' % str(datetime.now() - start_time))
+    # check inputs
+    if skip_uniref and uniref_loc is not None:
+        raise ValueError('Cannot skip UniRef processing and provide a location of UniRef.'
+                         ' Skipping UniRef will cause provided UniRef file to not be used.')
+    
+    if select_db is not None:
+        miss_name = [i for i in select_db if i not in database_settings]
+        user_inputs = [i for i in locs if i not in select_db]
+        if len(miss_name) > 0:
+            LOGGER.error("Only the databases in the db list can be pased to select_db, "
+                            f"you passed {miss_name} which is/are not in the list,"
+                            f" select from {list(database_settings.keys())}.")
+            raise ValueError('Bad user input, see log')
+        
+        if len(user_inputs) > 0:
+            LOGGER.error(f"The user provided location for {user_inputs}, but required it not be used by proving"
+                             f" the select_db argument for other databases. This would suggest that the"
+                             " user may have made a mistake and so this error is rased.")
+            raise ValueError('Bad user input, see log')
+
+        database_settings = {i:database_settings[i] for i in select_db}
+
+
+    LOGGER.info('Database preparation started')
 
-    # move all files from temporary to output that will be kept
-    for db_name, output_db in output_dbs.items():
-        for db_file in glob('%s*' % output_db):
-            move(db_file, path.join(output_dir, path.basename(db_file)))
-        output_dbs[db_name] = path.join(output_dir, path.basename(output_db))
-    print('%s: Files moved to final destination' % str(datetime.now() - start_time))
+    # Download DBs
+    for i, j in database_settings.items():
+        if locs.get(i) is None:
+            LOGGER.info(f"Downloading {i}")
+            if i in process_functions:
+                locs[i] = download_functions[i](
+                    temporary, LOGGER, **j, verbose=verbose)
+            else:
+                locs[i] = download_functions[i](
+                    output_dir, LOGGER, **j, verbose=verbose)
+            j['Download time'] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S")
+            j['Origin'] = "Downloaded by DRAM"
+        else:
+            j = {k: "Unknown" for k in j}
+            j['Download time'] = "Unknown"
+            j['Origin'] = "Provided by user"
+            j['Original path'] = locs[i]
+            if i not in process_functions:
+                LOGGER.info(f"Copying {locs[i]} to output_dir")
+                locs[i] = copyfile(locs[i], path.join(output_dir, path.basename(locs[i])))
 
-    output_dbs['description_db_loc'] = path.realpath(path.join(output_dir, 'description_db.sqlite'))
+    LOGGER.info("All raw data files were downloaded successfully")
 
-    db_handler = DatabaseHandler()
-    db_handler.populate_description_db(output_dbs['description_db_loc'], update_config=False)
-    db_handler.set_database_paths(**output_dbs)
-    print('%s: DRAM description database populated' % str(datetime.now() - start_time))
+    # Process databases
+    for i in locs: 
+        processed_locs = {} 
+        if i in process_functions:
+            LOGGER.info(f"Processing {i}")
+            processed_locs = process_functions[i](locs[i], output_dir, LOGGER, 
+                                                       threads=threads, verbose=verbose, **process_settings[i])
+        else:
+            processed_locs = {i:locs[i]}
+        for k, v in processed_locs.items():
+            final_dest = path.join(output_dir, path.basename(v))
+            if v != final_dest:
+                for db_file in glob('%s*' % v):
+                    move(db_file, path.join(output_dir, path.basename(db_file)))
+                v = path.join(output_dir, path.basename(v))
+            # update_dram_forms the settings per OUTPUT fill, including the process_settings
+            #  and database_settings, which are per input file.
+            if db_handler.config.get('setup_info') is None:
+                db_handler.config['setup_info'] = {}
+            db_handler.config['setup_info'][k] = {**dram_settings[k], **process_settings[i], 
+                                                  **database_settings[i]}
+            db_handler.set_database_paths(**{f"{k}_loc":v})
+            db_handler.write_config()
+            LOGGER.info(f'Moved {k} to final destination, configuration updated')
+
+    LOGGER.info('Populating the description db, this may take some time')
+    db_handler.config['description_db'] = path.realpath(path.join(output_dir, 'description_db.sqlite'))
+    db_handler.write_config()
+    db_handler.populate_description_db(db_handler.config['description_db'], select_db, update_config=False)
+    # todo make db handler such that the destruction on success write_config
+    db_handler.write_config()
+    LOGGER.info('DRAM description database populated')
 
     if not keep_database_files:
         rmtree(temporary)
-    print('%s: Database preparation completed' % str(datetime.now() - start_time))
+    LOGGER.info('Database preparation completed')
 
 
 def update_dram_forms(output_dir, branch='master'):
     if not path.isdir(output_dir):
         mkdir(output_dir)
-
     form_locs = dict()
-    form_locs['genome_summary_form_loc'] = download_and_process_genome_summary_form(output_dir, branch)
-    form_locs['module_step_form_loc'] = download_and_process_module_step_form(output_dir, branch)
-    form_locs['etc_module_database_loc'] = download_and_process_etc_module_database(output_dir, branch)
-    form_locs['function_heatmap_form_loc'] = download_and_process_function_heatmap_form(output_dir, branch)
-    form_locs['amg_database_loc'] = download_and_process_amg_database(output_dir, branch)
+    form_locs['genome_summary_form_loc'] = download_genome_summary_form(output_dir, branch)
+    form_locs['module_step_form_loc'] = download_module_step_form(output_dir, branch)
+    form_locs['etc_module_database_loc'] = download_etc_module_database(output_dir, branch)
+    form_locs['function_heatmap_form_loc'] = download_function_heatmap_form(output_dir, branch)
+    form_locs['amg_database_loc'] = download_amg_database(output_dir, branch)
     db_handler = DatabaseHandler()
     db_handler.set_database_paths(**form_locs)
diff --git a/mag_annotator/database_setup.py b/mag_annotator/database_setup.py
index 2747a748..c0c2216d 100644
--- a/mag_annotator/database_setup.py
+++ b/mag_annotator/database_setup.py
@@ -1,3 +1,6 @@
+"""
+Defines the classes that are used to acsess sql data with sqlalchemy. Each data set that gets its descriptions stored in sql needs its database stored there also.
+"""
 from sqlalchemy import Column, String, create_engine
 from sqlalchemy.ext.declarative import declarative_base
 
@@ -69,15 +72,35 @@ class DbcanDescription(Base):
     id = Column(String(30), primary_key=True, nullable=False, index=True)
 
     description = Column(String(1000))
+    ec = Column(String(1000))
 
     @property
     def serialize(self):
         return {
             'dbcan_id': self.id,
             'dbcan_description': self.description,
+            'dbcan_subfam_ec': self.ec,
         }
 
 
+# DBCAN_SUBFAM_EC_TABLE_NAME = 'dbcan_subfam_ec'
+
+
+# class DbcanSubfamEC(Base):
+#     __tablename__ = DBCAN_SUBFAM_EC_TABLE_NAME
+# 
+#     id = Column(String(30), primary_key=True, nullable=False, index=True)
+# 
+#     description = Column(String(1000))
+# 
+#     @property
+#     def serialize(self):
+#         return {
+#             'dbcan_id': self.id,
+#             'dbcan_subfam_ec': self.description,
+#         }
+
+
 VIRAL_DESCRIPTION_TABLE_NAME = 'viral_description'
 
 
@@ -141,6 +164,7 @@ def create_description_db(db_loc):
                             UNIREF_DESCRIPTION_TABLE_NAME: UniRefDescription,
                             PFAM_DESCRIPTION_TABLE_NAME: PfamDescription,
                             DBCAN_DESCRIPTION_TABLE_NAME: DbcanDescription,
+                            # DBCAN_SUBFAM_EC_TABLE_NAME: DbcanSubfamEC,
                             VIRAL_DESCRIPTION_TABLE_NAME: ViralDescription,
                             PEPTIDASE_DESCRIPTION_TABLE_NAME: PeptidaseDescription,
                             VOGDB_DESCRIPTION_TABLE_NAME: VOGDBDescription}
diff --git a/mag_annotator/pull_sequences.py b/mag_annotator/pull_sequences.py
index d76e7e48..d0046dca 100644
--- a/mag_annotator/pull_sequences.py
+++ b/mag_annotator/pull_sequences.py
@@ -3,9 +3,11 @@
 from skbio import write as write_sequence
 from os import mkdir, path
 import warnings
+import logging
 
 from mag_annotator.summarize_vgfs import filter_to_amgs
-from mag_annotator.utils import get_ids_from_row
+from mag_annotator.utils import setup_logger
+from mag_annotator.summarize_genomes import get_ids_from_annotations_by_row
 from mag_annotator.database_handler import DatabaseHandler
 
 # TODO: filter by taxonomic level, completeness, contamination
@@ -40,9 +42,8 @@ def get_genes_from_identifiers(annotations, genes=None, fastas=None, scaffolds=N
 
         # make a dictionary of genes to
         gene_to_ids = dict()
-        for i, row in annotations_to_keep.iterrows():
-            row_ids = get_ids_from_row(row)
-            if len(row_ids) > 0:
+        for i, row_ids in get_ids_from_annotations_by_row(annotations_to_keep).iteritems():
+           if len(row_ids) > 0:
                 gene_to_ids[i] = set(row_ids)
 
         # get genes with ids
@@ -69,55 +70,71 @@ def get_genes_from_identifiers(annotations, genes=None, fastas=None, scaffolds=N
     return annotation_genes_to_keep
 
 
-def pull_sequences(input_annotations, input_fasta, output_fasta, fastas=None, scaffolds=None, genes=None,
-                   identifiers=None, categories=None, taxonomy=None, completeness=None, contamination=None,
+def pull_sequences(input_tsv, input_fasta, output_fasta, fastas=None, scaffolds=None, genes=None,
+                   identifiers=None, adjective_sheet:str=None, categories=None, taxonomy=None, completeness=None, contamination=None,
                    amg_flags=None, aux_scores=None, virsorter_category=None, putative_amgs=False,
                    max_auxiliary_score=3, remove_transposons=False, remove_fs=False, custom_distillate=None):
-    annotations = pd.read_csv(input_annotations, sep='\t', index_col=0)
-
-    # first filter based on specific names
-    annotation_genes_to_keep = get_genes_from_identifiers(annotations, genes, fastas, scaffolds, identifiers,
-                                                          categories, custom_distillate)
-    annotations = annotations.loc[annotation_genes_to_keep]
-    if len(annotations) == 0:
-        raise ValueError("Categories or identifiers provided yielded no annotations")
-
-    # DRAM specific filtering
-    if taxonomy is not None:
-        taxonomy = set(taxonomy)
-        annotations = annotations.loc[[len(set(i.split(';')) & taxonomy) > 0 for i in annotations['bin_taxonomy']]]
-    if completeness is not None:
-        annotations = annotations.loc[annotations['bin_completeness'].astype(float) > completeness]
-    if contamination is not None:
-        annotations = annotations.loc[annotations['bin_contamination'].astype(float) < contamination]
-    if len(annotations) == 0:
-        raise ValueError("DRAM filters yielded no annotations")
-
-    # DRAM-v specific filtering
-    if putative_amgs:  # get potential amgs
-        # annotations = filter_to_amgs(annotations.fillna(''), max_aux=max_auxiliary_score,
-        #                              remove_transposons=remove_transposons, remove_fs=remove_fs, remove_js=remove_js)
-        annotations = filter_to_amgs(annotations.fillna(''), max_aux=max_auxiliary_score,
-                                     remove_transposons=remove_transposons, remove_fs=remove_fs)
-    else:
-        # filter based on virsorter categories
-        if virsorter_category is not None:
-            annotations = annotations.loc[[i in virsorter_category for i in annotations.virsorter]]
-        # filter based on aux scores
-        if aux_scores is not None:
-            annotations = annotations.loc[[i in aux_scores for i in annotations.auxiliary_score]]
-        # filter based on amg flags
-        if amg_flags is not None:
-            amg_flags = set(amg_flags)
-            annotations = annotations.loc[[len(set(i) & amg_flags) > 0 if not pd.isna(i) else False
-                                           for i in annotations.amg_flags]]
-    if len(annotations) == 0:
-        raise ValueError("DRAM-v filters yielded no annotations")
-
-    # make output
-    output_fasta_generator = (i for i in read_sequence(input_fasta, format='fasta')
-                              if i.metadata['id'] in annotations.index)
-    write_sequence(output_fasta_generator, format='fasta', into=output_fasta)
+
+    #setup logger
+    logger = logging.getLogger('strainer_log')
+    setup_logger(logger)
+
+    try:
+        annotations = pd.read_csv(input_tsv, sep='\t', index_col=0)
+        if adjective_sheet is not None:
+            adjective_sheet = pd.read_csv(input_tsv, sep='\t', index_col=0) 
+            annotations = annotations.loc[adjective_sheet.index]
+            breakpoint()
+        annotation_genes_to_keep = get_genes_from_identifiers(annotations, genes, fastas, scaffolds, identifiers,
+                                                              categories, custom_distillate)
+        annotations = annotations.loc[annotation_genes_to_keep]
+        if len(annotations) == 0:
+            raise ValueError("Categories or identifiers provided yielded no annotations")
+
+
+        # DRAM specific filtering
+        if taxonomy is not None:
+            taxonomy = set(taxonomy)
+            annotations = annotations.loc[[len(set(i.split(';')) & taxonomy) > 0 for i in annotations['bin_taxonomy']]]
+        if completeness is not None:
+            annotations = annotations.loc[annotations['bin_completeness'].astype(float) > completeness]
+        if contamination is not None:
+            annotations = annotations.loc[annotations['bin_contamination'].astype(float) < contamination]
+        if len(annotations) == 0:
+            raise ValueError("DRAM filters yielded no annotations")
+        # DRAM-v specific filtering
+        if putative_amgs:  # get potential amgs
+            annotations = filter_to_amgs(annotations.fillna(''), max_aux=max_auxiliary_score,
+                                         remove_transposons=remove_transposons, remove_fs=remove_fs)
+        else:
+            # filter based on virsorter categories
+            if virsorter_category is not None:
+                annotations = annotations.loc[[i in virsorter_category for i in annotations.virsorter]]
+            # filter based on aux scores
+            if aux_scores is not None:
+                annotations = annotations.loc[[i in aux_scores for i in annotations.auxiliary_score]]
+            # filter based on amg flags
+            if amg_flags is not None:
+                amg_flags = set(amg_flags)
+                annotations = annotations.loc[[len(set(i) & amg_flags) > 0 if not pd.isna(i) else False
+                                               for i in annotations.amg_flags]]
+        if len(annotations) == 0:
+            raise ValueError("DRAM-v filters yielded no annotations")
+
+        # make output
+        output_fasta_generator = (i for i in read_sequence(input_fasta, format='fasta')
+                                  if i.metadata['id'] in annotations.index)
+        write_sequence(output_fasta_generator, format='fasta', into=output_fasta)
+    except KeyError as err:
+        logger.error(err)
+        logger.critical("It looks like your input files are not appropriate for the filter you are trying to apply."
+                     " For example using a Viral or AMG filter on an annotations that has no viral information.")
+        
+        raise err
+    except Exception as err:
+        logger.error(err)
+        logger.critical('Unknown error, exiting')
+        raise err
 
 
 def find_neighborhoods(annotations, genes_from_ids, distance_bp=None, distance_genes=None):
@@ -166,9 +183,17 @@ def get_gene_neighborhoods(input_file, output_dir, genes=None, identifiers=None,
 
     mkdir(output_dir)
 
+    #setup logger
+    # Get a logger
+    # if log_file_path is None:
+    log_file_path = path.join(output_dir, "Strainer.log")
+    logger = logging.getLogger('strainer_log')
+    setup_logger(logger, log_file_path)
+    logger.info(f"The log file is created at {log_file_path}")
+
     neighborhood_all_annotations = find_neighborhoods(annotations, genes_from_ids, distance_bp, distance_genes)
     neighborhood_all_annotations.to_csv(path.join(output_dir, 'neighborhood_annotations.tsv'), sep='\t')
-
+    logger.info("Neighborhood Annotations witten to tsv")
     # filter files if given
     if genes_loc is not None:
         output_fasta_generator = (i for i in read_sequence(genes_loc, format='fasta')
@@ -176,7 +201,7 @@ def get_gene_neighborhoods(input_file, output_dir, genes=None, identifiers=None,
         # TODO: potentially generate one fasta file per neighborhood
         write_sequence(output_fasta_generator, format='fasta',
                        into=path.join(output_dir, 'neighborhood_genes.%s' % genes_loc.split('.')[-1]))
-
+        logger.info("Gene Neighborhood fasta generated")
     if scaffolds_loc is not None:
         neighborhood_all_annotations['scaffold_mod'] = ['%s_%s' % (row['fasta'], row['scaffold'])
                                                         for i, row in neighborhood_all_annotations.iterrows()]
@@ -191,3 +216,4 @@ def get_gene_neighborhoods(input_file, output_dir, genes=None, identifiers=None,
                                                            neighborhood_frame['end_position'][-1]])
         write_sequence((i for i in neighborhood_scaffolds), format='fasta',
                        into=path.join(output_dir, 'neighborhood_scaffolds.fna'))
+        logger.info("Scaffolds Neighborhood fasta generated")
diff --git a/mag_annotator/summarize_genomes.py b/mag_annotator/summarize_genomes.py
index bda3e50e..1c635f3b 100644
--- a/mag_annotator/summarize_genomes.py
+++ b/mag_annotator/summarize_genomes.py
@@ -1,3 +1,7 @@
+"""This is the script that distills the genomes"""
+import logging
+from collections import Counter
+from itertools import chain
 import pandas as pd
 from collections import Counter, defaultdict
 from os import path, mkdir
@@ -9,7 +13,7 @@
 from datetime import datetime
 
 from mag_annotator.database_handler import DatabaseHandler
-from mag_annotator.utils import get_ids_from_annotation, get_ids_from_row, get_ordered_uniques
+from mag_annotator.utils import get_ordered_uniques, setup_logger
 
 # TODO: add RBH information to output
 # TODO: add flag to output table and not xlsx
@@ -17,20 +21,71 @@
 
 FRAME_COLUMNS = ['gene_id', 'gene_description', 'module', 'sheet', 'header', 'subheader']
 RRNA_TYPES = ['5S rRNA', '16S rRNA', '23S rRNA']
-HEATMAP_MODULES = ['M00001', 'M00004', 'M00008', 'M00009', 'M00012', 'M00165', 'M00173', 'M00374', 'M00375',
-                   'M00376', 'M00377', 'M00422', 'M00567']
+HEATMAP_MODULES = ['M00001', 'M00004', 'M00008', 'M00009', 'M00012', 'M00165', 'M00173', 
+                   'M00374', 'M00375', 'M00376', 'M00377', 'M00422', 'M00567']
 HEATMAP_CELL_HEIGHT = 10
 HEATMAP_CELL_WIDTH = 10
 KO_REGEX = r'^K\d\d\d\d\d$'
-ETC_COVERAGE_COLUMNS = ['module_id', 'module_name', 'complex', 'genome', 'path_length', 'path_length_coverage',
-                        'percent_coverage', 'genes', 'missing_genes', 'complex_module_name']
+ETC_COVERAGE_COLUMNS = ['module_id', 'module_name', 'complex', 'genome', 'path_length', 
+                        'path_length_coverage', 'percent_coverage', 'genes', 'missing_genes', 
+                        'complex_module_name']
 TAXONOMY_LEVELS = ['d', 'p', 'c', 'o', 'f', 'g', 's']
-
-
-def fill_genome_summary_frame(annotations, genome_summary_frame, groupby_column):
-    genome_summary_id_sets = [set([k.strip() for k in j.split(',')]) for j in genome_summary_frame['gene_id']]
-    for genome, frame in annotations.groupby(groupby_column, sort=False):
-        id_dict = get_ids_from_annotation(frame)
+COL_HEADER, COL_SUBHEADER, COL_MODULE, COL_GENE_ID, COL_GENE_DESCRIPTION = 'header', 'subheader', 'module', 'gene_id', 'gene_description'
+CONSTANT_DISTILLATE_COLUMNS = [COL_GENE_ID, COL_GENE_DESCRIPTION, COL_MODULE, COL_HEADER, COL_SUBHEADER]
+DISTILATE_SORT_ORDER_COLUMNS = [COL_HEADER, COL_SUBHEADER, COL_MODULE, COL_GENE_ID]
+EXCEL_MAX_CELL_SIZE = 32767
+
+ID_FUNCTION_DICT = { 
+    'kegg_genes_id': lambda x: [x],
+    'ko_id': lambda x: [j for j in x.split(',')],
+    'kegg_id': lambda x: [j for j in x.split(',')],
+    'kegg_hit': lambda x: [i[1:-1] for i in 
+                           re.findall(r'\[EC:\d*.\d*.\d*.\d*\]', x)],
+    'peptidase_family': lambda x: [j for j in x.split(';')],
+    'cazy_ids': lambda x: [i.split('_')[0] for i in x.split('; ')],
+    'cazy_id': lambda x: [i.split('_')[0] for i in x.split('; ')],
+    'cazy_hits': lambda x: [f"{i[1:3]}:{i[4:-1]}" for i in 
+                            re.findall(r'\(EC [\d+\.]+[\d-]\)', x)
+                            ] + [
+                            i[1:-1].split('_')[0] 
+                            for i in re.findall(r'\[[A-Z]*\d*?\]', x)],
+    'cazy_subfam_ec': lambda x: [f"EC:{i}" for i in 
+                                 re.findall(r'[\d+\.]+[\d-]', x)],
+    'pfam_hits': lambda x: [j[1:-1].split('.')[0]
+                            for j in re.findall(r'\[PF\d\d\d\d\d.\d*\]', x)],
+    'camper_id': lambda x: [x],
+    'fegenie_id': lambda x: [x],
+    'sulfur_id': lambda x: [x],
+    'methyl_id': lambda x: [i.split(' ')[0].strip() for i in x.split(',')]
+}
+
+
+def check_columns(data, logger):
+    functions = {i:j for i,j in ID_FUNCTION_DICT.items() if i in data.columns}
+    missing = [i for i in ID_FUNCTION_DICT if i not in data.columns]
+    logger.info("Note: the fallowing id fields "
+          f"were not in the annotations file and are not being used: {missing},"
+          f" but these are {list(functions.keys())}")
+
+
+def get_ids_from_annotations_by_row(data):
+    functions = {i:j for i,j in ID_FUNCTION_DICT.items() if i in data.columns}
+    out = data.apply(lambda x: {i for k, v in functions.items() if not pd.isna(x[k])
+                          for i in v(str(x[k])) if not pd.isna(i)}, axis=1)
+    return out
+
+
+def get_ids_from_annotations_all(data):
+    data =  get_ids_from_annotations_by_row(data)
+    data.apply(list)
+    out = Counter(chain(*data.values))
+    return out
+
+
+def fill_genome_summary_frame(annotations, genome_summary_frame, groupby_column, logger):
+    genome_summary_id_sets = [set([str(k).strip() for k in j.split(',')]) for j in genome_summary_frame['gene_id']]
+    def fill_a_frame(frame:pd.DataFrame):
+        id_dict = get_ids_from_annotations_all(frame)
         counts = list()
         for i in genome_summary_id_sets:
             identifier_count = 0
@@ -38,17 +93,19 @@ def fill_genome_summary_frame(annotations, genome_summary_frame, groupby_column)
                 if j in id_dict:
                     identifier_count += id_dict[j]
             counts.append(identifier_count)
-        genome_summary_frame[genome] = counts
+        return pd.Series(counts, index=genome_summary_frame.index)
+        # genome_summary_frame[genome] = counts
+    counts = annotations.groupby(groupby_column, sort=False).apply(fill_a_frame)
+    genome_summary_frame = pd.concat([genome_summary_frame, counts.T], axis=1)
     return genome_summary_frame
 
 
-def fill_genome_summary_frame_gene_names(annotations, genome_summary_frame, groupby_column):
+def fill_genome_summary_frame_gene_names(annotations, genome_summary_frame, groupby_column, logger):
     genome_summary_id_sets = [set([k.strip() for k in j.split(',')]) for j in genome_summary_frame['gene_id']]
     for genome, frame in annotations.groupby(groupby_column, sort=False):
         # make dict of identifiers to gene names
         id_gene_dict = defaultdict(list)
-        for gene, row in frame.iterrows():
-            ids = get_ids_from_row(row)
+        for gene, ids in get_ids_from_annotations_by_row(frame).iteritems():
             for id_ in ids:
                 id_gene_dict[id_].append(gene)
         # fill in genome summary_frame
@@ -109,10 +166,10 @@ def summarize_trnas(trnas_df, groupby_column='fasta'):
     return trna_frame
 
 
-def make_genome_summary(annotations, genome_summary_frame, trna_frame=None, rrna_frame=None, groupby_column='fasta'):
+def make_genome_summary(annotations, genome_summary_frame, logger, trna_frame=None, rrna_frame=None, groupby_column='fasta'):
     summary_frames = list()
     # get ko summaries
-    summary_frames.append(fill_genome_summary_frame(annotations, genome_summary_frame.copy(), groupby_column))
+    summary_frames.append(fill_genome_summary_frame(annotations, genome_summary_frame.copy(), groupby_column, logger))
 
     # add rRNAs
     if rrna_frame is not None:
@@ -127,12 +184,38 @@ def make_genome_summary(annotations, genome_summary_frame, trna_frame=None, rrna
     return summarized_genomes
 
 
+def split_column_str(names):
+    if len(names) < EXCEL_MAX_CELL_SIZE:
+        return [names]
+    out = ['']
+    name_list = names.split(',')
+    j = 0
+    for i in name_list:
+        if len(out[j]) + len(i) + 1 < EXCEL_MAX_CELL_SIZE:
+            out[j] = ','.join([out[j], i])
+        else:
+            j += 1
+            out += ['']
+    return out
+
+
+def split_names_to_long(col:pd.Series):
+    dex = col.index
+    splits = [split_column_str(i) for i in col.values]
+    ncols =  max([len(i) for i in splits])
+    col_names = [col.name if i == 0 else f"{col.name}[{i + 1}]" for i in range(ncols)]
+    return pd.DataFrame(splits, columns=col_names, index=dex).fillna('')
+
+
 def write_summarized_genomes_to_xlsx(summarized_genomes, output_file):
     # turn all this into an xlsx
     with pd.ExcelWriter(output_file) as writer:
         for sheet, frame in summarized_genomes.groupby('sheet', sort=False):
-            frame = frame.sort_values(['header', 'subheader', 'module', 'gene_id'])
+            frame = frame.sort_values(DISTILATE_SORT_ORDER_COLUMNS)
             frame = frame.drop(['sheet'], axis=1)
+            gene_columns = list(set(frame.columns) - set(CONSTANT_DISTILLATE_COLUMNS))
+            split_genes = pd.concat([split_names_to_long(frame[i].astype(str)) for i in gene_columns], axis=1)
+            frame = pd.concat([frame[CONSTANT_DISTILLATE_COLUMNS],  split_genes], axis=1)
             frame.to_excel(writer, sheet_name=sheet, index=False)
 
 
@@ -181,7 +264,8 @@ def make_genome_stats(annotations, rrna_frame=None, trna_frame=None, groupby_col
                     row.append('%s present' % sixteens.shape[0])
                     has_rrna.append(False)
         if trna_frame is not None:
-            row.append(trna_frame.loc[trna_frame[groupby_column] == genome].shape[0])  # TODO: remove psuedo from count?
+            # TODO: remove psuedo from count?
+            row.append(trna_frame.loc[trna_frame[groupby_column] == genome].shape[0])  
         if 'assembly quality' in columns:
             if frame['bin_completeness'][0] > 90 and frame['bin_contamination'][0] < 5 and np.all(has_rrna) and \
                len(set(trna_frame.loc[trna_frame[groupby_column] == genome].Type)) >= 18:
@@ -379,7 +463,7 @@ def make_etc_coverage_df(etc_module_df, annotations, groupby_column='fasta'):
         # go through each genome and check pathway coverage
         for group, frame in annotations.groupby(groupby_column):
             # get annotation genes
-            grouped_ids = set(get_ids_from_annotation(frame).keys())
+            grouped_ids = set(get_ids_from_annotations_all(frame).keys())
             path_len, path_coverage_count, path_coverage_percent, genes, missing_genes = \
                 get_module_coverage(module_net, grouped_ids)
             complex_module_name = 'Complex %s: %s' % (module_row['complex'].replace('Complex ', ''),
@@ -416,14 +500,14 @@ def make_etc_coverage_heatmap(etc_coverage, mag_order=None, module_order=None):
     return alt.hconcat(*charts, spacing=5, title=concat_title)
 
 
-def make_functional_df(annotations, function_heatmap_form, groupby_column='fasta'):
+def make_functional_df(annotations, function_heatmap_form, logger, groupby_column='fasta'):
     # clean up function heatmap form
     function_heatmap_form = function_heatmap_form.apply(lambda x: x.str.strip() if x.dtype == "object" else x)
     function_heatmap_form = function_heatmap_form.fillna('')
     # build dict of ids per genome
     genome_to_id_dict = dict()
     for genome, frame in annotations.groupby(groupby_column, sort=False):
-        id_list = get_ids_from_annotation(frame).keys()
+        id_list = get_ids_from_annotations_all(frame).keys()
         genome_to_id_dict[genome] = set(id_list)
     # build long from data frame
     rows = list()
@@ -469,18 +553,7 @@ def make_functional_heatmap(functional_df, mag_order=None):
                                 scale=alt.Scale(range=['#2ca25f', '#e5f5f9']))
         # define chart
         # TODO: Figure out how to angle title to take up less space
-        c = alt.Chart(frame, title=alt.TitleParams(group)).encode(
-            x=alt.X('function_name', title=None, axis=alt.Axis(labelLimit=0, labelAngle=90), sort=function_order),
-            tooltip=[alt.Tooltip('genome', title='Genome'),
-                     alt.Tooltip('category', title='Category'),
-                     alt.Tooltip('subcategory', title='Subcategory'),
-                     alt.Tooltip('function_ids', title='Function IDs'),
-                     alt.Tooltip('function_name', title='Function'),
-                     alt.Tooltip('long_function_name', title='Description'),
-                     alt.Tooltip('gene_symbol', title='Gene Symbol')]
-        ).mark_rect().encode(y=y, color=rect_colors).properties(
-            width=chart_width,
-            height=chart_height)
+        c = alt.Chart(frame, title=alt.TitleParams(group)).encode( x=alt.X('function_name', title=None, axis=alt.Axis(labelLimit=0, labelAngle=90), sort=function_order), tooltip=[alt.Tooltip('genome', title='Genome'), alt.Tooltip('category', title='Category'), alt.Tooltip('subcategory', title='Subcategory'), alt.Tooltip('function_ids', title='Function IDs'), alt.Tooltip('function_name', title='Function'), alt.Tooltip('long_function_name', title='Description'), alt.Tooltip('gene_symbol', title='Gene Symbol')]).mark_rect().encode(y=y, color=rect_colors).properties( width=chart_width, height=chart_height)
         charts.append(c)
     # merge and return
     function_heatmap = alt.hconcat(*charts, spacing=5)
@@ -488,14 +561,14 @@ def make_functional_heatmap(functional_df, mag_order=None):
 
 
 # TODO: refactor this to handle splitting large numbers of genomes into multiple heatmaps here
-def fill_liquor_dfs(annotations, module_nets, etc_module_df, function_heatmap_form, groupby_column='fasta'):
+def fill_liquor_dfs(annotations, module_nets, etc_module_df, function_heatmap_form, logger, groupby_column='fasta'):
     module_coverage_frame = make_module_coverage_frame(annotations, module_nets, groupby_column)
 
     # make ETC frame
     etc_coverage_df = make_etc_coverage_df(etc_module_df, annotations, groupby_column)
 
     # make functional frame
-    function_df = make_functional_df(annotations, function_heatmap_form, groupby_column)
+    function_df = make_functional_df(annotations, function_heatmap_form, logger, groupby_column)
 
     return module_coverage_frame, etc_coverage_df, function_df
 
@@ -551,15 +624,25 @@ def make_strings_no_repeats(genome_taxa_dict):
     return labels
 
 
-def summarize_genomes(input_file, trna_path=None, rrna_path=None, output_dir='.', groupby_column='fasta',
-                      custom_distillate=None, distillate_gene_names=False, genomes_per_product=1000):
-    start_time = datetime.now()
+def summarize_genomes(input_file, trna_path=None, rrna_path=None, output_dir='.', 
+                      groupby_column='fasta', log_file_path=None, custom_distillate=None,
+                      distillate_gene_names=False, genomes_per_product=1000):
+    # make output folder
+    mkdir(output_dir)
+    if log_file_path is None:
+        log_file_path = path.join(output_dir, "Distillation.log")
+    logger = logging.getLogger('distillation_log')
+    setup_logger(logger, log_file_path)
+    logger.info(f"The log file is created at {log_file_path}")
 
     # read in data
     annotations = pd.read_csv(input_file, sep='\t', index_col=0)
     if 'bin_taxnomy' in annotations:
         annotations = annotations.sort_values('bin_taxonomy')
 
+    # Check the columns are present
+    check_columns(annotations, logger)
+
     if trna_path is None:
         trna_frame = None
     else:
@@ -570,41 +653,41 @@ def summarize_genomes(input_file, trna_path=None, rrna_path=None, output_dir='.'
         rrna_frame = pd.read_csv(rrna_path, sep='\t')
 
     # get db_locs and read in dbs
-    database_handler = DatabaseHandler()
-    if 'genome_summary_form' not in database_handler.dram_sheet_locs:
+    database_handler = DatabaseHandler(logger)
+    if 'genome_summary_form' not in database_handler.config["dram_sheets"]:
         raise ValueError('Genome summary form location must be set in order to summarize genomes')
-    if 'module_step_form' not in database_handler.dram_sheet_locs:
+    if 'module_step_form' not in database_handler.config["dram_sheets"]:
         raise ValueError('Module step form location must be set in order to summarize genomes')
-    if 'function_heatmap_form' not in database_handler.dram_sheet_locs:
+    if 'function_heatmap_form' not in database_handler.config["dram_sheets"]:
         raise ValueError('Functional heat map form location must be set in order to summarize genomes')
 
     # read in dbs
-    genome_summary_form = pd.read_csv(database_handler.dram_sheet_locs['genome_summary_form'], sep='\t')
+    genome_summary_form = pd.read_csv(database_handler.config["dram_sheets"]['genome_summary_form'], sep='\t')
     if custom_distillate is not None:
         genome_summary_form = pd.concat([genome_summary_form, pd.read_csv(custom_distillate, sep='\t')])
     genome_summary_form = genome_summary_form.drop('potential_amg', axis=1)
-    module_steps_form = pd.read_csv(database_handler.dram_sheet_locs['module_step_form'], sep='\t')
-    function_heatmap_form = pd.read_csv(database_handler.dram_sheet_locs['function_heatmap_form'], sep='\t')
-    etc_module_df = pd.read_csv(database_handler.dram_sheet_locs['etc_module_database'], sep='\t')
-    print('%s: Retrieved database locations and descriptions' % (str(datetime.now() - start_time)))
-
-    # make output folder
-    mkdir(output_dir)
+    module_steps_form = pd.read_csv(
+        database_handler.config["dram_sheets"]['module_step_form'], sep='\t')
+    function_heatmap_form = pd.read_csv(
+        database_handler.config["dram_sheets"]['function_heatmap_form'], sep='\t')
+    etc_module_df = pd.read_csv(
+        database_handler.config["dram_sheets"]['etc_module_database'], sep='\t')
+    logger.info('Retrieved database locations and descriptions')
 
     # make genome stats
     genome_stats = make_genome_stats(annotations, rrna_frame, trna_frame, groupby_column=groupby_column)
     genome_stats.to_csv(path.join(output_dir, 'genome_stats.tsv'), sep='\t', index=None)
-    print('%s: Calculated genome statistics' % (str(datetime.now() - start_time)))
+    logger.info('Calculated genome statistics')
 
     # make genome metabolism summary
     genome_summary = path.join(output_dir, 'metabolism_summary.xlsx')
     if distillate_gene_names:
-        summarized_genomes = fill_genome_summary_frame_gene_names(annotations, genome_summary_form, groupby_column)
+        summarized_genomes = fill_genome_summary_frame_gene_names(annotations, genome_summary_form, groupby_column, logger)
     else:
-        summarized_genomes = make_genome_summary(annotations, genome_summary_form, trna_frame, rrna_frame,
+        summarized_genomes = make_genome_summary(annotations, genome_summary_form, logger, trna_frame, rrna_frame,
                                                  groupby_column)
     write_summarized_genomes_to_xlsx(summarized_genomes, genome_summary)
-    print('%s: Generated genome metabolism summary' % (str(datetime.now() - start_time)))
+    logger.info('Generated genome metabolism summary')
 
     # make liquor
     if 'bin_taxonomy' in annotations:
@@ -635,7 +718,7 @@ def summarize_genomes(input_file, trna_path=None, rrna_path=None, output_dir='.'
             genomes = genome_order[start:end]
             annotations_subset = annotations.loc[[genome in genomes for genome in annotations[groupby_column]]]
             dfs = fill_liquor_dfs(annotations_subset, module_nets, etc_module_df, function_heatmap_form,
-                                  groupby_column='fasta')
+                                  logger, groupby_column='fasta')
             module_coverage_df_subset, etc_coverage_df_subset, function_df_subset = dfs
             module_coverage_dfs.append(module_coverage_df_subset)
             etc_coverage_dfs.append(etc_coverage_df_subset)
@@ -644,15 +727,17 @@ def summarize_genomes(input_file, trna_path=None, rrna_path=None, output_dir='.'
                                          genomes, labels)
             liquor.save(path.join(output_dir, 'product_%s.html' % i))
         liquor_df = make_liquor_df(pd.concat(module_coverage_dfs), pd.concat(etc_coverage_dfs), pd.concat(function_dfs))
-        liquor_df.to_csv(path.join(output_dir, 'product.tsv'), sep='\t')
     else:
-        module_coverage_df, etc_coverage_df, function_df = fill_liquor_dfs(annotations, module_nets,
-                                                                           etc_module_df,
-                                                                           function_heatmap_form,
-                                                                           groupby_column=groupby_column)
+        module_coverage_df, etc_coverage_df, function_df = fill_liquor_dfs(
+            annotations,
+            module_nets,
+            etc_module_df,
+            function_heatmap_form,
+            logger,
+            groupby_column=groupby_column)
         liquor_df = make_liquor_df(module_coverage_df, etc_coverage_df, function_df)
-        liquor_df.to_csv(path.join(output_dir, 'product.tsv'), sep='\t')
-        liquor = make_liquor_heatmap(module_coverage_df, etc_coverage_df, function_df, genome_order, labels)
+        liquor = make_liquor_heatmap(module_coverage_df, etc_coverage_df, function_df, genome_order, None)
         liquor.save(path.join(output_dir, 'product.html'))
-    print('%s: Generated product heatmap and table' % (str(datetime.now() - start_time)))
-    print("%s: Completed distillation" % str(datetime.now() - start_time))
+    liquor_df.to_csv(path.join(output_dir, 'product.tsv'), sep='\t')
+    logger.info('Generated product heatmap and table')
+    logger.info("Completed distillation")
diff --git a/mag_annotator/summarize_vgfs.py b/mag_annotator/summarize_vgfs.py
index 07403ddb..75d7a4e3 100644
--- a/mag_annotator/summarize_vgfs.py
+++ b/mag_annotator/summarize_vgfs.py
@@ -8,7 +8,8 @@
 import warnings
 
 from mag_annotator.database_handler import DatabaseHandler
-from mag_annotator.utils import get_ids_from_row, get_ids_from_annotation, get_ordered_uniques
+from mag_annotator.summarize_genomes import get_ids_from_annotations_by_row, \
+    get_ids_from_annotations_all, get_ordered_uniques, check_columns
 
 VOGDB_TYPE_NAMES = {'Xr': 'Viral replication genes', 'Xs': 'Viral structure genes',
                     'Xh': 'Viral genes with host benefits', 'Xp': 'Viral genes with viral benefits',
@@ -32,7 +33,7 @@ def add_custom_ms(annotations, distillate_form):
         if 'M' in row['amg_flags']:
             new_amg_flags.append(row['amg_flags'])
         else:
-            gene_annotations = set(get_ids_from_annotation(pd.DataFrame(row).transpose()).keys())
+            gene_annotations = set(get_ids_from_annotations_all(pd.DataFrame(row).transpose()).keys())
             if len(metabolic_genes & gene_annotations) > 0:
                 new_amg_flags.append(row['amg_flags'] + 'M')
             else:
@@ -104,8 +105,9 @@ def make_viral_stats_table(annotations, potential_amgs, groupby_column='scaffold
 
 def make_viral_distillate(potential_amgs, genome_summary_frame):
     rows = list()
+    potential_amgs['ids'] = get_ids_from_annotations_by_row(potential_amgs)
     for gene, row in potential_amgs.iterrows():
-        gene_ids = get_ids_from_row(row) & set(genome_summary_frame.index)
+        gene_ids = row.ids & set(genome_summary_frame.index)
         if len(gene_ids) > 0:
             for gene_id in gene_ids:
                 gene_summary = genome_summary_frame.loc[gene_id]
@@ -150,8 +152,7 @@ def make_viral_functional_df(annotations, genome_summary_frame, groupby_column='
     # build dict of ids per genome
     vgf_to_id_dict = defaultdict(defaultdict_list)
     for vgf, frame in annotations.groupby(groupby_column, sort=False):
-        for gene, row in frame.iterrows():
-            id_list = get_ids_from_row(row)
+        for gene, id_list in get_ids_from_annotations_by_row(frame).iteritems():
             for id_ in id_list:
                 vgf_to_id_dict[vgf][id_].append(gene)
     # build long from data frame
@@ -213,10 +214,18 @@ def make_viral_functional_heatmap(functional_df, vgf_order=None):
 #                    remove_fs=False, remove_js=False, custom_distillate=None):
 def summarize_vgfs(input_file, output_dir, groupby_column='scaffold', max_auxiliary_score=3,
                    remove_transposons=False, remove_fs=False, custom_distillate=None):
-    start_time = datetime.now()
+    # make output folder
+    mkdir(output_dir)
+    if log_file_path is None:
+        log_file_path = path.join(output_dir, "Distillation.log")
+    logger = logging.getLogger('distillation_log')
+    setup_logger(logger, log_file_path)
+    logger.info(f"The log file is created at {log_file_path}")
+
 
     # set up
     annotations = pd.read_csv(input_file, sep='\t', index_col=0).fillna('')
+    check_columns(annotations, logger)
     database_handler = DatabaseHandler()
     if database_handler.dram_sheet_locs.get('genome_summary_form') is None:
         raise ValueError('Genome summary form location must be set in order to summarize genomes')
@@ -227,23 +236,23 @@ def summarize_vgfs(input_file, output_dir, groupby_column='scaffold', max_auxili
         genome_summary_form = pd.concat([genome_summary_form, custom_distillate_form])
         # add M's from custom distillate
         annotations['amg_flags'] = add_custom_ms(annotations, custom_distillate_form)
-    print('%s: Retrieved database locations and descriptions' % (str(datetime.now() - start_time)))
+    logger.info('Retrieved database locations and descriptions')
 
     # get potential AMGs
     # potential_amgs = filter_to_amgs(annotations.fillna(''), max_aux=max_auxiliary_score,
     #                                 remove_transposons=remove_transposons, remove_fs=remove_fs, remove_js=remove_js)
     potential_amgs = filter_to_amgs(annotations, max_aux=max_auxiliary_score,
                                     remove_transposons=remove_transposons, remove_fs=remove_fs)
-    print('%s: Determined potential amgs' % (str(datetime.now() - start_time)))
+    logger.info('Determined potential amgs')
 
     # make distillate
     viral_genome_stats = make_viral_stats_table(annotations, potential_amgs, groupby_column)
     viral_genome_stats.to_csv(path.join(output_dir, 'vMAG_stats.tsv'), sep='\t')
-    print('%s: Calculated viral genome statistics' % (str(datetime.now() - start_time)))
+    logger.info('Calculated viral genome statistics')
 
     viral_distillate = make_viral_distillate(potential_amgs, genome_summary_form)
     viral_distillate.to_csv(path.join(output_dir, 'amg_summary.tsv'), sep='\t', index=None)
-    print('%s: Generated AMG summary' % (str(datetime.now() - start_time)))
+    logger.info('Generated AMG summary')
 
     # make liquor
     vgf_order = make_vgf_order(potential_amgs)
@@ -251,5 +260,5 @@ def summarize_vgfs(input_file, output_dir, groupby_column='scaffold', max_auxili
     viral_function_df = make_viral_functional_df(potential_amgs, genome_summary_form, groupby_column=groupby_column)
     viral_functional_heatmap = make_viral_functional_heatmap(viral_function_df, vgf_order)
     alt.hconcat(amg_column, viral_functional_heatmap, spacing=5).save(path.join(output_dir, 'product.html'))
-    print('%s: Generated product heatmap' % (str(datetime.now() - start_time)))
-    print("%s: Completed distillation" % str(datetime.now() - start_time))
+    logger.info('Generated product heatmap')
+    logger.info("Completed distillation")
diff --git a/mag_annotator/utils.py b/mag_annotator/utils.py
index 24486189..f96ea311 100644
--- a/mag_annotator/utils.py
+++ b/mag_annotator/utils.py
@@ -1,50 +1,110 @@
 import re
 import subprocess
-from collections import Counter
-from os import path
-from urllib.request import urlopen
+from os import path, stat
+from urllib.request import urlopen, urlretrieve
+from urllib.error import URLError
 import pandas as pd
+import logging
+from typing import Callable
 
+HMMSCAN_ALL_COLUMNS = ['query_id', 'query_ascession', 'query_length', 'target_id', 'target_ascession', 'target_length',
+                       'full_evalue', 'full_score', 'full_bias', 'domain_number', 'domain_count', 'domain_cevalue',
+                       'domain_ievalue', 'domain_score', 'domain_bias', 'target_start', 'target_end', 'alignment_start',
+                       'alignment_end', 'query_start', 'query_end', 'accuracy', 'description']
+HMMSCAN_COLUMN_TYPES = [str, str, int, str, str, int, float, float, float, int, int, float, float, float, float, int,
+                        int, int, int, int, int, float, str]
+BOUTFMT6_COLUMNS = ['qId', 'tId', 'seqIdentity', 'alnLen', 'mismatchCnt', 'gapOpenCnt', 'qStart', 'qEnd', 'tStart',
+                    'tEnd', 'eVal', 'bitScore']
 
-def download_file(url, output_file=None, verbose=True):
+
+def download_file(url: str, output_file: str, logger: logging.Logger, alt_urls: list[str] = None, verbose = True):
     # TODO: catching error 4 and give error message to retry or retry automatically
-    if verbose:
-        print('downloading %s' % url)
-    if output_file is None:
-        return urlopen(url).read().decode('utf-8')
-    else:
-        run_process(['wget', '-O', output_file, url], verbose=verbose)
+    links = [url] if alt_urls is None else [url] + alt_urls
+    for l in links: 
+        if verbose:
+            print('downloading %s' % url)
+        try:
+            urlretrieve(l, output_file)
+            return
+        except BaseException as error:
+            # BaseException is good http was to exact
+            logger.warning(f"Something went wrong with the download of the url: {l}")
+            logger.warning(error)
+    raise URLError("DRAM whas not able to download a key database, check the logg for details")
+    # run_process(['wget', '-O', output_file, url], verbose=verbose)
+
+
+def setup_logger(logger, *log_file_paths, level=logging.INFO):
+    logger.setLevel(level)
+    formatter = logging.Formatter('%(asctime)s - %(message)s')
+    # create console handler
+    ch = logging.StreamHandler()
+    ch.setLevel(logging.INFO)
+    # create formatter and add it to the handlers
+    ch.setFormatter(formatter)
+    logger.addHandler(ch)
+    for log_file_path in log_file_paths:
+        fh = logging.FileHandler(log_file_path)
+        fh.setLevel(logging.INFO)
+        fh.setFormatter(formatter)
+        # add the handlers to the logger
+        logger.addHandler(fh)
 
 
-def run_process(command, shell=False, capture_stdout=True, check=True, verbose=False):
-    """Standardization of parameters for using subprocess.run, provides verbose mode and option to run via shell"""
-    stdout = subprocess.DEVNULL
-    stderr = subprocess.DEVNULL
-    if verbose:
-        stdout = None
-        stderr = None
+def run_process(command, logger, shell:bool=False, capture_stdout:bool=True, save_output:str=None, 
+                check:bool=False, stop_on_error:bool=True, verbose:bool=False) -> str:
+    """
+    Standardization of parameters for using subprocess.run, provides verbose mode and option to run via shell
+    """
+    # TODO just remove check
+    try:
+        results = subprocess.run(command, check=check, shell=shell,
+                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
+    except subprocess.CalledProcessError as error:
+        logger.critical(f'The subcommand {command} experienced an error')
+        if stop_on_error:
+            raise error
+    if results.returncode != 0:
+        logger.critical(f'The subcommand {command} experienced an error: {results.stderr}')
+        logging.debug(results.stdout)
+        if stop_on_error:
+           raise subprocess.SubprocessError(f"The subcommand {' '.join(command)} experienced an error, see the log for more info.")
+    if save_output is not None:
+        with open(save_output, 'w') as out:
+            out.write(results.stdout)
     if capture_stdout:
-        return subprocess.run(command, check=check, shell=shell, stdout=subprocess.PIPE,
-                              stderr=stderr).stdout.decode(errors='ignore')
-    else:
-        subprocess.run(command, check=check, shell=shell, stdout=stdout, stderr=stderr)
+        return results.stdout
+
+
+# TODO: refactor following to methods to a shared run hmm step and individual get description steps
+def parse_hmmsearch_domtblout(file):
+    df_lines = list()
+    for line in open(file):
+        if not line.startswith('#'):
+            line = line.split()
+            line = line[:22] + [' '.join(line[22:])]
+            df_lines.append(line)
+    hmmsearch_frame = pd.DataFrame(df_lines, columns=HMMSCAN_ALL_COLUMNS)
+    for i, column in enumerate(hmmsearch_frame.columns):
+        hmmsearch_frame[column] = hmmsearch_frame[column].astype(HMMSCAN_COLUMN_TYPES[i])
+    return hmmsearch_frame
 
 
-def make_mmseqs_db(fasta_loc, output_loc, create_index=True, threads=10, verbose=False):
+def make_mmseqs_db(fasta_loc, output_loc, logger, create_index=True, threads=10, verbose=False):
     """Takes a fasta file and makes a mmseqs2 database for use in blast searching and hmm searching with mmseqs2"""
-    run_process(['mmseqs', 'createdb', fasta_loc, output_loc], verbose=verbose)
+    run_process(['mmseqs', 'createdb', fasta_loc, output_loc], logger, verbose=verbose)
     if create_index:
         tmp_dir = path.join(path.dirname(output_loc), 'tmp')
-        run_process(['mmseqs', 'createindex', output_loc, tmp_dir, '--threads', str(threads)], verbose=verbose)
+        run_process(['mmseqs', 'createindex', output_loc, tmp_dir, '--threads', str(threads)], logger, verbose=verbose)
 
 
-def multigrep(search_terms, search_against, split_char='\n', output='.'):
+def multigrep(search_terms, search_against, logger, split_char='\n', output='.'):
     # TODO: multiprocess this over the list of search terms
     """Search a list of exact substrings against a database, takes name of mmseqs db index with _h to search against"""
     hits_file = path.join(output, 'hits.txt')
     with open(hits_file, 'w') as f:
         f.write('%s\n' % '\n'.join(search_terms))
-    results = run_process(['grep', '-a', '-F', '-f', hits_file, search_against], capture_stdout=True, verbose=False)
+    results = run_process(['grep', '-a', '-F', '-f', hits_file, search_against], logger, capture_stdout=True, verbose=False)
     processed_results = [i.strip() for i in results.strip().split(split_char)
                          if len(i) > 0]
     # remove(hits_file)
@@ -63,72 +123,6 @@ def merge_files(files_to_merge, outfile, has_header=False):
                 outfile_handle.write(f.read())
 
 
-def get_ids_from_annotation(frame):
-    id_list = list()
-    # get kegg gene ids
-    if 'kegg_genes_id' in frame:
-        id_list += [j.strip() for i in frame.kegg_genes_id.dropna() for j in i.split(',')]
-    # get kegg orthology ids
-    if 'ko_id' in frame:
-        id_list += [j.strip() for i in frame.ko_id.dropna() for j in i.split(',')]
-    # Get old ko numbers
-    # TODO Get rid of this old stuff
-    if 'kegg_id' in frame:
-        id_list += [j.strip() for i in frame.kegg_id.dropna() for j in i.split(',')]
-    # get kegg ec numbers
-    if 'kegg_hit' in frame:
-        for kegg_hit in frame.kegg_hit.dropna():
-            id_list += [i[1:-1] for i in re.findall(r'\[EC:\d*.\d*.\d*.\d*\]', kegg_hit)]
-    # get merops ids
-    if 'peptidase_family' in frame:
-        id_list += [j.strip() for i in frame.peptidase_family.dropna() for j in i.split(';')]
-    # get cazy ids
-    if 'cazy_id' in frame:
-        id_list += [j for i in frame.cazy_id.dropna() for j in i.split('; ')]
-    # get cazy ec numbers
-    if 'cazy_hits' in frame:
-        id_list += [f"{j[1:3]}:{j[4:-1]}" for i in frame.cazy_hits.dropna()
-                    for j in re.findall(r'\(EC [\d+\.]+[\d-]\)', i)]
-        # get cazy ec numbers from old format
-        # TODO Don't have this in DRAM 2
-        for cazy_hit in frame.cazy_hits.dropna():
-            id_list += [i[1:-1].split('_')[0] for i in re.findall(r'\[[A-Z]*\d*?\]', cazy_hit)]
-    # get pfam ids
-    if 'pfam_hits' in frame:
-        id_list += [j[1:-1].split('.')[0] for i in frame.pfam_hits.dropna()
-                    for j in re.findall(r'\[PF\d\d\d\d\d.\d*\]', i)]
-    return Counter(id_list)
-
-
-#TODO unify this with get_ids_from_annotation
-def get_ids_from_row(row):
-    id_list = list()
-    # get kegg gene ids
-    if 'kegg_genes_id' in row and not pd.isna(row['kegg_genes_id']):
-        id_list += row['kegg_genes_id']
-    # get kegg orthology ids
-    if 'ko_id' in row and not pd.isna(row['ko_id']):
-        id_list += [j for j in row['ko_id'].split(',')]
-    # Get old ko numbers
-    # TODO Get rid of this old stuff
-    if 'kegg_id' in row and not pd.isna(row['kegg_id']):
-        id_list += [j for j in row['kegg_id'].split(',')]
-    # get ec numbers
-    if 'kegg_hit' in row and not pd.isna(row['kegg_hit']):
-        id_list += [i[1:-1] for i in re.findall(r'\[EC:\d*.\d*.\d*.\d*\]', row['kegg_hit'])]
-    # get merops ids
-    if 'peptidase_family' in row and not pd.isna(row['peptidase_family']):
-        id_list += [j for j in row['peptidase_family'].split(';')]
-    # get cazy ids
-    if 'cazy_hits' in row and not pd.isna(row['cazy_hits']):
-        id_list += [i[1:-1].split('_')[0] for i in re.findall(r'\[[A-Z]*\d*?\]', row['cazy_hits'])]
-    # get pfam ids
-    if 'pfam_hits' in row and not pd.isna(row['pfam_hits']):
-        id_list += [j[1:-1].split('.')[0]
-                    for j in re.findall(r'\[PF\d\d\d\d\d.\d*\]', row['pfam_hits'])]
-    return set(id_list)
-
-
 def divide_chunks(l, n):
     # looping till length l
     for i in range(0, len(l), n):
@@ -150,4 +144,123 @@ def remove_suffix(text, suffix):
 def get_ordered_uniques(seq):
     seen = set()
     seen_add = seen.add
-    return [x for x in seq if not (x in seen or seen_add(x))]
+    return [x for x in seq if not (x in seen or seen_add(x) or pd.isna(x))]
+
+
+def get_best_hits(query_db, target_db, logger, output_dir='.', query_prefix='query', target_prefix='target',
+                  bit_score_threshold=60, threads=10, verbose=False):
+    """Uses mmseqs2 to do a blast style search of a query db against a target db, filters to only include best hits
+    Returns a file location of a blast out format 6 file with search results
+    """
+    # make query to target db
+    tmp_dir = path.join(output_dir, 'tmp')
+    query_target_db = path.join(output_dir, '%s_%s.mmsdb' % (query_prefix, target_prefix))
+    run_process(['mmseqs', 'search', query_db, target_db, query_target_db, tmp_dir, '--threads', str(threads)],
+                 logger, verbose=verbose)
+    # filter query to target db to only best hit
+    query_target_db_top = path.join(output_dir, '%s_%s.tophit.mmsdb' % (query_prefix, target_prefix))
+    run_process(['mmseqs', 'filterdb', query_target_db, query_target_db_top, '--extract-lines', '1'], logger,
+                verbose=verbose)
+    # filter query to target db to only hits with min threshold
+    query_target_db_top_filt = path.join(output_dir, '%s_%s.tophit.minbitscore%s.mmsdb'
+                                         % (query_prefix, target_prefix, bit_score_threshold))
+    run_process(['mmseqs', 'filterdb', '--filter-column', '2', '--comparison-operator', 'ge', '--comparison-value',
+                 str(bit_score_threshold), '--threads', str(threads), query_target_db_top, query_target_db_top_filt],
+                logger, verbose=verbose)
+    # convert results to blast outformat 6
+    forward_output_loc = path.join(output_dir, '%s_%s_hits.b6' % (query_prefix, target_prefix))
+    run_process(['mmseqs', 'convertalis', query_db, target_db, query_target_db_top_filt, forward_output_loc,
+                 '--threads', str(threads)], logger, verbose=verbose)
+    return forward_output_loc
+
+
+def get_reciprocal_best_hits(query_db, target_db, logger, output_dir='.', query_prefix='query', target_prefix='target',
+                             bit_score_threshold=60, rbh_bit_score_threshold=350, threads=10, verbose=False):
+    """Take results from best hits and use for a reciprocal best hits search"""
+    # TODO: Make it take query_target_db as a parameter
+    # create subset for second search
+    query_target_db_top_filt = path.join(output_dir, '%s_%s.tophit.minbitscore%s.mmsdb'
+                                         % (query_prefix, target_prefix, bit_score_threshold))  # I DON'T LIKE THIS
+    query_target_db_filt_top_swapped = path.join(output_dir, '%s_%s.minbitscore%s.tophit.swapped.mmsdb'
+                                                 % (query_prefix, target_prefix, bit_score_threshold))
+    # swap queries and targets in results database
+    run_process(['mmseqs', 'swapdb', query_target_db_top_filt, query_target_db_filt_top_swapped, '--threads',
+                 str(threads)], logger, verbose=verbose)
+    target_db_filt = path.join(output_dir, '%s.filt.mmsdb' % target_prefix)
+    # create a subdatabase of the target database with the best hits as well as the index of the target database
+    run_process(['mmseqs', 'createsubdb', query_target_db_filt_top_swapped, target_db, target_db_filt],
+                logger, verbose=verbose)
+    run_process(['mmseqs', 'createsubdb', query_target_db_filt_top_swapped, '%s_h' % target_db,
+                 '%s_h' % target_db_filt], logger, verbose=verbose)
+
+    return get_best_hits(target_db_filt, query_db, logger, output_dir, target_prefix, query_prefix, rbh_bit_score_threshold,
+                         threads, verbose)
+
+
+def run_hmmscan(genes_faa:str, db_loc:str, db_name:str, output_loc:str, formater:Callable,
+                logger:logging.Logger, threads:int=2, db_handler=None, verbose:bool=False):
+    output = path.join(output_loc, f'{db_name}_results.unprocessed.b6')
+    run_process(['hmmsearch', '--domtblout', output, '--cpu', str(threads), db_loc, genes_faa], logger, verbose=verbose)
+    # Parse hmmsearch output
+    if not (path.isfile(output) and stat(output).st_size > 0):
+        return pd.DataFrame()
+    hits = parse_hmmsearch_domtblout(output)
+    if len(hits) < 1:
+        return pd.DataFrame()
+    return formater(hits)
+
+
+def get_sig_row(row, evalue_lim:float=1e-15):
+    """Check if hmm match is significant, based on dbCAN described parameters"""
+    tstart, tend, tlen, evalue = row[['target_start', 'target_end', 'target_length', 'full_evalue']].values
+    perc_cov = (tend - tstart)/tlen
+    if perc_cov >= .35 and evalue <= evalue_lim:
+        return True
+    else:
+        return False
+
+
+#TODO decide if we need use_hmmer_thresholds:bool=False
+def generic_hmmscan_formater(hits:pd.DataFrame,  db_name:str, hmm_info_path:str=None, top_hit:bool=True):
+    if hmm_info_path is None:
+        hmm_info = None
+        hits_sig = hits[hits.apply(get_sig_row, axis=1)]
+    else:
+        hmm_info = pd.read_csv(hmm_info_path, sep='\t', index_col=0)
+        hits_sig = sig_scores(hits, hmm_info)
+    if len(hits_sig) == 0:
+        # if nothing significant then return nothing, don't get descriptions
+        return pd.DataFrame()
+    if top_hit:
+        # Get the best hits
+        hits_sig = hits_sig.sort_values('full_evalue').drop_duplicates(subset=["query_id"])
+    hits_df = hits_sig[['target_id', 'query_id']]
+    hits_df.set_index('query_id', inplace=True, drop=True)
+    hits_df.rename_axis(None, inplace=True)
+    hits_df.columns = [f"{db_name}_id"]
+    if hmm_info is not None:
+        hits_df = hits_df.merge(hmm_info[['definition']], how='left', left_on=f"{db_name}_id", right_index=True)
+        hits_df.rename(columns={'definition': f"{db_name}_hits"}, inplace=True)
+    return hits_df
+
+
+def sig_scores(hits:pd.DataFrame, score_db:pd.DataFrame) -> pd.DataFrame:
+    is_sig = list()
+    for i, frame in hits.groupby('target_id'):
+        row = score_db.loc[i]
+        if row['score_type'] == 'domain':
+            score = frame.domain_score
+        elif row['score_type'] == 'full':
+            score = frame.full_score
+        elif row['score_type'] == '-':
+            continue
+        else:
+            raise ValueError(row['score_type'])
+        frame = frame.loc[score.astype(float) > float(row.threshold)]
+        is_sig.append(frame)
+    if len(is_sig) > 0:
+        return pd.concat(is_sig)
+    else:
+        return pd.DataFrame()
+
+
diff --git a/scripts/DRAM-setup.py b/scripts/DRAM-setup.py
index b0489037..31eefb48 100644
--- a/scripts/DRAM-setup.py
+++ b/scripts/DRAM-setup.py
@@ -4,8 +4,8 @@
 
 from mag_annotator.database_processing import prepare_databases, update_dram_forms, \
     DEFAULT_DBCAN_DATE, DEFAULT_DBCAN_RELEASE, DEFAULT_UNIREF_VERSION
-from mag_annotator.database_handler import set_database_paths, print_database_locations, populate_description_db, \
-    export_config, import_config
+from mag_annotator.database_handler import DatabaseHandler,  set_database_paths,  populate_description_db, \
+    export_config, import_config, print_database_locations, print_database_settings
 from mag_annotator import __version__ as version
 
 
@@ -27,6 +27,8 @@
                                                      formatter_class=argparse.ArgumentDefaultsHelpFormatter)
     print_db_locs_parser = subparsers.add_parser('print_config', help="Print database locations",
                                                  formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    print_db_settings_parser = subparsers.add_parser('print_settings', help="Print database settings",
+                                                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
     import_config_parser = subparsers.add_parser('import_config', help="Import CONFIG file",
                                                  formatter_class=argparse.ArgumentDefaultsHelpFormatter)
     export_config_parser = subparsers.add_parser('export_config', help="Export CONFIG file",
@@ -55,7 +57,7 @@ def print_version():
                                          "not impact DRAM distillation")
     prepare_dbs_parser.add_argument('--pfam_loc', default=None,
                                     help="File path to pfam-A full file, if already downloaded (Pfam-A.full.gz)")
-    prepare_dbs_parser.add_argument('--pfam_hmm_dat', default=None,
+    prepare_dbs_parser.add_argument('--pfam_hmm_loc', default=None,
                                     help="pfam hmm .dat file to get PF descriptions, if already downloaded "
                                          "(Pfam-A.hmm.dat.gz)")
     prepare_dbs_parser.add_argument('--dbcan_loc', default=None, help="File path to dbCAN, if already downloaded "
@@ -89,27 +91,34 @@ def print_version():
                                     help="Keep unporcessed database files")
     prepare_dbs_parser.add_argument('--threads', default=10, type=int,
                                     help="Number of threads to use building mmseqs2 databases")
+    prepare_dbs_parser.add_argument('--select_db', action='append',
+                                    help="The db or dbs the you want to update if you don't want to do a full upgrade")
+    prepare_dbs_parser.add_argument('--clear_config', default=False, action='store_true', help="By default"
+                                    " when you set up a new db the old db is cleared, but not if you use select_db."
+                                    " If you use select db you can add this argument, forcing the old config to be cleared.(beta)")
     prepare_dbs_parser.add_argument('--verbose', default=False, action='store_true', help="Make it talk more")
     prepare_dbs_parser.set_defaults(func=prepare_databases)
 
     # parser for setting database locations when you already have processed database files
-    set_db_locs_parser.add_argument('--kegg_db_loc', default=None, help='mmseqs2 database file from kegg .pep file')
+    set_db_locs_parser.add_argument('--kegg_loc', default=None, help='mmseqs2 database file from kegg .pep file')
     set_db_locs_parser.add_argument('--kofam_hmm_loc', default=None, help='hmm file for KOfam, already processed with'
                                                                           'hmmpress')
     set_db_locs_parser.add_argument('--kofam_ko_list_loc', default=None, help='KOfam ko list file')
-    set_db_locs_parser.add_argument('--uniref_db_loc', default=None, help='mmseqs2 database file from uniref .faa')
-    set_db_locs_parser.add_argument('--pfam_db_loc', default=None, help='mmseqs2 database file from pfam .hmm')
-    set_db_locs_parser.add_argument('--pfam_hmm_dat', default=None, help='pfam hmm .dat file to get PF descriptions')
-    set_db_locs_parser.add_argument('--dbcan_db_loc', default=None,
+    set_db_locs_parser.add_argument('--uniref_loc', default=None, help='mmseqs2 database file from uniref .faa')
+    set_db_locs_parser.add_argument('--pfam_loc', default=None, help='mmseqs2 database file from pfam .hmm')
+    set_db_locs_parser.add_argument('--pfam_hmm_loc', default=None, help='pfam hmm .dat file to get PF descriptions')
+    set_db_locs_parser.add_argument('--dbcan_loc', default=None,
                                     help='hmm file for dbcan, already processed with hmmpress')
     set_db_locs_parser.add_argument('--dbcan_fam_activities', default=None, help='CAZY family activities file')
-    set_db_locs_parser.add_argument('--vogdb_db_loc', default=None,
+    set_db_locs_parser.add_argument('--dbcan_subfam_ec', default=None, help='CAZY sub-family ECs file')
+    set_db_locs_parser.add_argument('--vogdb_loc', default=None,
                                     help='hmm file for vogdb, already processed with hmmpress')
     set_db_locs_parser.add_argument('--vog_annotations', default=None,
                                     help='vog annotations file') # add loc to vog_annotations to match the rest
-    set_db_locs_parser.add_argument('--viral_db_loc', default=None,
+
+    set_db_locs_parser.add_argument('--viral_refseq_loc', default=None,
                                     help='mmseqs2 database file from ref seq viral gene collection')
-    set_db_locs_parser.add_argument('--peptidase_db_loc', default=None,
+    set_db_locs_parser.add_argument('--peptidase_loc', default=None,
                                     help='mmseqs2 database file from MEROPS database')
     set_db_locs_parser.add_argument('--description_db_loc', default=None,
                                     help="Location to write description sqlite db")
@@ -128,6 +137,8 @@ def print_version():
     update_description_db_parser.add_argument('--config_loc', help="Location of CONFIG file to use for finding "
                                                                    "databases, by default the location in the built in "
                                                                    "CONFIG will be used")
+    update_description_db_parser.add_argument('--select_db', action='append',
+                                    help="The db or dbs the you want to update if you don't want to do a full upgrade")
     update_description_db_parser.set_defaults(func=populate_description_db)
 
     # parser for updating DRAM databases only
@@ -141,6 +152,10 @@ def print_version():
                                                                    "default the locations from the built in CONFIG "
                                                                    "will be used")
     print_db_locs_parser.set_defaults(func=print_database_locations)
+    print_db_settings_parser.add_argument('--config_loc', help="Location of CONFIG to print locations from, by "
+                                                                   "default the locations from the built in CONFIG "
+                                                                   "will be used")
+    print_db_settings_parser.set_defaults(func=print_database_settings)
 
     # parser for printing out or saving CONFIG to file
     export_config_parser.add_argument('--output_file', help="File to save exported CONFIG file to, by default will"
diff --git a/scripts/DRAM-v.py b/scripts/DRAM-v.py
index 01e57ba9..337348e6 100644
--- a/scripts/DRAM-v.py
+++ b/scripts/DRAM-v.py
@@ -62,8 +62,8 @@
                                        help="Location of file with custom HMM cutoffs and descriptions, can be used "
                                             "multiple times.")
     annotate_parser.add_argument('--use_uniref', action='store_true', default=False,
-                                 help='Annotate these fastas against UniRef, drastically increases run time and memory '
-                                      'requirements')
+                                 help='Annotate these fastas against UniRef, drastically increases'
+                                      ' run time and memory requirements')
     annotate_parser.add_argument('--low_mem_mode', action='store_true', default=False,
                                  help='Skip annotating with uniref and use kofam instead of KEGG genes even if '
                                       'provided. Drastically decreases memory usage')
@@ -84,6 +84,8 @@
                                 help="Do not consider genes on scaffolds with transposons as potential AMGs")
     distill_parser.add_argument("--remove_fs", default=False, action='store_true',
                                 help="Do not consider genes near ends of scaffolds as potential AMGs")
+    distill_parser.add_argument('--log_file_path', 
+                                       help="A name and loctation for the log file")
     # distill_parser.add_argument("--remove_js", default=False, action='store_true',
     #                             help="Do not consider genes on possible non-viral contigs as potential AMGs")
     distill_parser.add_argument("--custom_distillate", help="Custom distillate form to add your own modules")
diff --git a/scripts/DRAM.py b/scripts/DRAM.py
index 8c14c869..223365fd 100644
--- a/scripts/DRAM.py
+++ b/scripts/DRAM.py
@@ -2,7 +2,7 @@
 
 import argparse
 
-from mag_annotator.annotate_bins import annotate_bins_cmd, annotate_called_genes_cmd, merge_annotations_cmd
+from mag_annotator.annotate_bins import annotate_bins, annotate_called_genes_cmd, merge_annotations_cmd
 from mag_annotator.summarize_genomes import summarize_genomes
 from mag_annotator.pull_sequences import pull_sequences, get_gene_neighborhoods
 
@@ -35,6 +35,9 @@
     annotate_parser.add_argument('-o', '--output_dir', help="output directory")
     annotate_parser.add_argument('--min_contig_size', type=int, default=2500,
                                  help='minimum contig size to be used for gene prediction')
+    annotate_parser.add_argument('--config_loc', default=None,
+                                       help='location of an alternive config file that will over write the original at run time,'
+                                       ' but not be saved or modified')
     prodigal_mode_choices = ['train', 'meta', 'single']
     annotate_parser.add_argument('--prodigal_mode', type=str, default='meta', choices=prodigal_mode_choices,
                                  help='Mode of prodigal to use for gene calling. NOTE: normal or single mode require '
@@ -81,12 +84,14 @@
     annotate_parser.add_argument('--keep_tmp_dir', action='store_true', default=False)
     annotate_parser.add_argument('--threads', type=int, default=10, help='number of processors to use')
     annotate_parser.add_argument('--verbose', action='store_true', default=False)
-    annotate_parser.set_defaults(func=annotate_bins_cmd)
+    annotate_parser.set_defaults(func=annotate_bins)
 
     # parser for annotating already called genes
     annotate_genes_parser.add_argument('-i', '--input_faa', help="fasta file, optionally with wildcards to point to "
                                                                  "individual MAGs", required=True)
-    annotate_genes_parser.add_argument('-o', '--output_dir', help="output directory")
+    annotate_genes_parser.add_argument('-o', '--output_dir', help="output directory", required=True)
+    annotate_genes_parser.add_argument('--log_file_path', 
+                                       help="A name and loctation for the log file")
     annotate_genes_parser.add_argument('--bit_score_threshold', type=int, default=60,
                                        help='minimum bitScore of search to retain hits')
     annotate_genes_parser.add_argument('--rbh_bit_score_threshold', type=int, default=350,
@@ -110,9 +115,14 @@
     annotate_genes_parser.add_argument('--use_uniref', action='store_true', default=False,
                                        help='Annotate these fastas against UniRef, drastically increases run time and '
                                             'memory requirements')
+    annotate_genes_parser.add_argument('--use_vogdb', action='store_true', default=False,
+                                 help='Annotate these fastas against VOGDB, drastically decreases run time')
     annotate_genes_parser.add_argument('--low_mem_mode', action='store_true', default=False,
                                        help='Skip annotating with uniref and use kofam instead of KEGG genes even if '
                                             'provided. Drastically decreases memory usage')
+    annotate_genes_parser.add_argument('--config_loc', default=None,
+                                       help='location of an alternive config file that will over write the original at run time,'
+                                       ' but not be saved or modified')
     annotate_genes_parser.add_argument('--keep_tmp_dir', action='store_true', default=False)
     annotate_genes_parser.add_argument('--threads', type=int, default=10, help='number of processors to use')
     annotate_genes_parser.add_argument('--verbose', action='store_true', default=False)
@@ -121,6 +131,8 @@
     # parser for summarizing genomes
     distill_parser.add_argument("-i", "--input_file", help="Annotations path")
     distill_parser.add_argument("-o", "--output_dir", help="Directory to write summarized genomes")
+    distill_parser.add_argument('--log_file_path', 
+                                       help="A name and loctation for the log file")
     distill_parser.add_argument("--rrna_path", help="rRNA output from annotation")
     distill_parser.add_argument("--trna_path", help="tRNA output from annotation")
     distill_parser.add_argument("--groupby_column", help="Column from annotations to group as organism units",
@@ -136,7 +148,10 @@
 
     # parser for getting genes
     input_group = strainer_parser.add_argument_group('Input and output files')
-    input_group.add_argument('-i', '--input_annotations', required=True, help='annotations file to pull genes from')
+    input_group.add_argument('-i', '--input_tsv', required=True, help="annotations file"
+                             " to pull genes from")
+    input_group.add_argument('--adjective_sheet', required=False, help='Output tsv file for strainer.'
+                             ' Use with the genes faa')
     input_group.add_argument('-f', '--input_fasta', required=True, help='fasta file to filter')
     input_group.add_argument('-o', '--output_fasta', default='pull_genes.fasta',
                              help='location to write filtered fasta')
diff --git a/setup.py b/setup.py
index 8cf163f5..5231731d 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
 from mag_annotator import __version__ as version
 from os import path
 
-__author__ = 'shafferm'
+__author__ = 'shafferm, rmflynn'
 __version__ = version
 
 here = path.abspath(path.dirname(__file__))


Test patch:
diff --git a/mag_annotator/fasta_dup_name_test.py b/mag_annotator/fasta_dup_name_test.py
new file mode 100644
index 00000000..65e8cdd8
--- /dev/null
+++ b/mag_annotator/fasta_dup_name_test.py
@@ -0,0 +1,37 @@
+"A simple script to check if there are groups of names in a set of fasta files"
+from itertools import permutations
+from collections import Counter
+
+DFT_HEAD_CHAR = '>'
+
+
+def fasta_dup_check(fasta:str, head_char=DFT_HEAD_CHAR) -> set:
+    with open(fasta) as fa:
+        headers = [line[1:].strip() for line in fa if line[0] == head_char]
+    header_set = set(headers)
+    if len(headers) >  len(header_set):
+        raise ValueError(f"The FASTA file {fasta} contains duplicate headers,"
+                         " you must correct this before continuing. The duplicate"
+                         f" headers are: {[k for k, v in Counter(headers).items() if v > 1]}")
+    return header_set
+
+
+def __check_sets(i, j):
+    if len(i[0]) + len(j[0]) > len(i[0].union(j[0])):
+        dup_headers = [k for k, v in Counter(list(i[0]) + list(j[0])).items() if v > 1]
+        if len(dup_headers) < 100:
+            raise ValueError(f"The FASTA files {i[1]} and {j[1]} contains duplicate headers,"
+                             " you must correct this before continuing. The duplicate"
+                             f" headers are {dup_headers}")
+        else:
+            raise ValueError(f"The FASTA files {i[1]} and {j[1]} contains duplicate headers,"
+                             " you must correct this before continuing. The first 100 duplicate"
+                             f" headers are {dup_headers[:100]}")
+
+
+def fastas_dup_check(fastas:list, head_char=DFT_HEAD_CHAR) -> bool:
+    headers = [fasta_dup_check(fasta, head_char) for fasta in fastas]
+    if sum([len(i) for i in headers]) > len(set().union(*headers)):
+        for i in permutations(zip(headers, fastas), 2):
+            __check_sets(i[0], i[1])
+    return True
diff --git a/tests/data/camper_test_annotations.tsv b/tests/data/camper_test_annotations.tsv
new file mode 100644
index 00000000..b2e31b93
--- /dev/null
+++ b/tests/data/camper_test_annotations.tsv
@@ -0,0 +1,27 @@
+	fasta	CAMPER_hits	CAMPER_rank	CAMPER_bitScore	CAMPER_id	CAMPER_definition	CAMPER_search_type
+camper_test_genes_20100900_E1D_13_c_000000004265_21	camper_test_genes	D00017;CarB	B	191.0	D00017	CarB;caffeyl-CoA synthetase 	blast
+camper_test_genes_20100900_E1D_13_c_000000004192_11	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_10	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_9	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_8	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_7	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_6	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_5	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_4	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_3	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_2	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_1	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_11	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_10	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_9	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_8	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_7	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_6	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_5	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_4	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_3	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_2	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004227_5	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004272_1	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_12	camper_test_genes						
+camper_test_genes_20100900_E1D_13_c_000000004192_13	camper_test_genes						
diff --git a/tests/data/camper_test_annotations_one.tsv b/tests/data/camper_test_annotations_one.tsv
new file mode 100644
index 00000000..5242c648
--- /dev/null
+++ b/tests/data/camper_test_annotations_one.tsv
@@ -0,0 +1,2 @@
+	fasta	CAMPER_hits	CAMPER_rank	CAMPER_bitScore	CAMPER_id	CAMPER_definition	CAMPER_search_type
+20100900_E1D_13_c_000000004265_21	genes	D00017;CarB	B	191.0	D00017	CarB;caffeyl-CoA synthetase 	blast
diff --git a/tests/data/camper_test_distillate.tsv b/tests/data/camper_test_distillate.tsv
new file mode 100644
index 00000000..93fe9cee
--- /dev/null
+++ b/tests/data/camper_test_distillate.tsv
@@ -0,0 +1,340 @@
+gene_id	gene_description	module	header	subheader	specific_reaction	oxygen	EC	Notes	genes
+K19065,EC:1.14.13.23	mobA; 3-hydroxybenzoate 4-monooxygenase [EC:1.14.13.23]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;3-hydroxybenzoic_acid	3-hydroxybenzoate conversion to protocatechuic acid (oxic)	step 1	3-hydroxybenzoate => 3,4-dihydroxybenzoate	oxic	EC:1.14.13.23		0
+K16270	todE;3-methylcatechol 2,3-dioxygenase [EC:1.13.11.-]	Polyphenols;Other_Polyphenols;Other_Polyphenols;3-methylcatechol	3-methylcatechol degradation (oxic)	step 1	3-methylcatechol => 2-Hydroxy-6-keto-2,4-heptadienoate	oxic			0
+K10702	todF;2-hydroxy-6-oxohepta-2,4-dienoate hydrolase [EC:3.7.1.25]	Product of: 3-Methylcatechol	3-methylcatechol degradation (oxic)	step 2	2-Hydroxy-6-keto-2,4-heptadienoate => 2-Hydroxy-2,4-pentadienoate + Acetate	oxic	EC:3.7.1.25		0
+K04105,K20458EC:6.2.1.27,EC:6.2.1.25	4-hydroxybenzoate-CoA ligase [EC:6.2.1.27 6.2.1.25]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;4-Hydroxybenzoic_acid	4-hydroxybenzoate conversion to benzoyl-CoA (anoxic)	step 1	4-Hydroxybenzoate => 4-Hydroxybenzoyl-CoA	anoxic	EC:6.2.1.27,EC:6.2.1.25		0
+K04108	4-hydroxybenzoyl-CoA reductase subunit alpha [EC:1.1.7.1]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;4-Hydroxybenzoyl-CoA	4-hydroxybenzoate conversion to benzoyl-CoA (anoxic)	step 2 subunit A	4-Hydroxybenzoyl-CoA => Benzoyl-CoA	anoxic	EC:1.1.7.11		0
+K04109	4-hydroxybenzoyl-CoA reductase subunit beta [EC:1.1.7.1]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;4-Hydroxybenzoyl-CoA	4-hydroxybenzoate conversion to benzoyl-CoA (anoxic)	step 2 subunit B	4-Hydroxybenzoyl-CoA => Benzoyl-CoA	anoxic	EC:1.1.7.11		0
+K04107,EC:1.1.7.11	4-hydroxybenzoyl-CoA reductase subunit gamma [EC:1.1.7.1]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;4-Hydroxybenzoyl-CoA	4-hydroxybenzoate conversion to benzoyl-CoA (anoxic)	step 2 subunit C	4-Hydroxybenzoyl-CoA => Benzoyl-CoA	anoxic	EC:1.1.7.11		0
+K00483,EC:1.14.14.9	hpaB; 4-hydroxyphenylacetate 3-monooxygenase [EC:1.14.14.9]	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;4-Hydroxyphenylacetic_Acid	4-Hydroxyphenylacetate conversion to Homoprotocatechuic Acid (oxic)	step 1	4-hydroxyphenylacetate => 3,4-dihydroxyphenylacetate	oxic	EC:1.14.14.9		0
+K22553	4-methoxybenzoate monooxygenase (O-demethylating) [EC:1.14.99.15]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;4-Methoxybenzoate	4-Methoxybenzoate conversion (oxic)	step 1	4-Methoxybenzoate => 4-Hydroxybenzoate + Formaldehyde	oxic	EC:1.14.99.15	feeds to K00481	0
+K15060	ligX;5,5'-dehydrodivanillate O-demethylase oxygenase subunit	Polyphenols;Lignin;;	5,5'-dehydrodivanillate conversion to Vanillate (oxic)	step 1 subunit A	5,5'-dehydrodivanillate => 2,2',3-trihydroxy-3'-methoxy-5,5'-dicarboxybiphenyl	oxic			0
+K24244	LigX;5,5'-dehydrodivanillate O-demethylase ferredoxin subunit	Polyphenols;Lignin;;	5,5'-dehydrodivanillate conversion to Vanillate (oxic)	step 1 subunit B	5,5'-dehydrodivanillate => 2,2',3-trihydroxy-3'-methoxy-5,5'-dicarboxybiphenyl	oxic			0
+K24245	ligX;5,5'-dehydrodivanillate O-demethylase ferredoxin reductase subunit	Polyphenols;Lignin;;	5,5'-dehydrodivanillate conversion to Vanillate (oxic)	step 1 subunit C	5,5'-dehydrodivanillate => 2,2',3-trihydroxy-3'-methoxy-5,5'-dicarboxybiphenyl	oxic			0
+K15061	LigZ;OH_DDVA oxygenase	Product of: Model_Lignin	5,5'-dehydrodivanillate conversion to Vanillate (oxic)	step 2	2,2',3-trihydroxy-3'-methoxy-5,5'-dicarboxybiphenyl => OH-DDVA meta-cleavage product	oxic			0
+K15062	ligY;OH-DDVA meta-cleavage compound hydrolase	Product of: Model_Lignin	5,5'-dehydrodivanillate conversion to Vanillate (oxic)	step 3	OH-DDVA meta-cleavage product => 5-carboxyvanillate	oxic			0
+K15063	ligW;5-carboxyvanillate decarboxylase	Product of: Model_Lignin	5,5'-dehydrodivanillate conversion to Vanillate (oxic)	step 4	5-carboxyvanillate => vanillate	oxic			0
+K03268,EC:1.14.12.3,EC:1.14.12.11,EC:1.14.12.26	benzene/toluene/chlorobenzene dioxygenase subunit alpha [EC:1.14.12.3 1.14.12.11 1.14.12.26]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Catechol (oxic)	step 1 subunit A	Benzene => cis-1,2-Dihydrobenzene-1,2-diol	oxic	EC:1.14.12.3,EC:1.14.12.11EC:1.14.12.26		0
+K16268	benzene/toluene/chlorobenzene dioxygenase subunit beta [EC:1.14.12.3 1.14.12.11 1.14.12.26] [RN:R03543 R03559 R05429 R06831 R06856 R09151 R09152]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Catechol (oxic)	step 1 subunit B	Benzene => cis-1,2-Dihydrobenzene-1,2-diol	oxic	EC:1.14.12.3,EC:1.14.12.11EC:1.14.12.26		0
+K18089	benzene/toluene/chlorobenzene dioxygenase ferredoxin component	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Catechol (oxic)	step 1 subunit C	Benzene => cis-1,2-Dihydrobenzene-1,2-diol	oxic			0
+K18090	benzene/toluene/chlorobenzene dioxygenase ferredoxin reductase component [EC:1.18.1.3 1.18.1.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Catechol (oxic)	step 1 subunit D	Benzene => cis-1,2-Dihydrobenzene-1,2-diol	oxic	EC:1.18.1.3		0
+K16269,EC:1.3.1.19,EC:1.3.1.119	cis-1,2-dihydrobenzene-1,2-diol/chlorobenzene dihydrodiol dehydrogenase [EC:1.3.1.19 1.3.1.119]	Product of: Benzene	Benzene Conversion to Catechol (oxic)	step 2	cis-1,2-Dihydrobenzene-1,2-diol => Catechol	oxic	EC:1.3.1.19,EC:1.3.1.119	feeds to catechol meta-cleavage	0
+K16249	dmpK; phenol hydroxylase P0 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Phenol (oxic)	subunit 0	Benzene => Phenol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16243	dmpL; Phenol hydroxylase P1 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Phenol (oxic)	subunit 1	Benzene => Phenol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16244	dmpM; phenol hydroxylase P2 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Phenol (oxic)	subunit 2	Benzene => Phenol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16242	dmpN; phenol hydroxylase P3 protein [EC:1.14.13.-] [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Phenol (oxic)	subunit 3	Benzene => Phenol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16245	dmpO; phenol hydroxylase P4 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Phenol (oxic)	subunit 4	Benzene => Phenol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16246	dmpP; phenol hydroxylase P5 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene	Benzene Conversion to Phenol (oxic)	subunit 5	Benzene => Phenol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K05549, EC:1.14.12.10	benA;benzoate/toluate 1,2-dioxygenase subunit alpha [EC:1.14.12.10 1.14.12.-] [RN:R05290 R05291 R05428 R05621 R05622 R05665 R08100 R08101 R08108 R08109 R08110]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoic_Acid	Benzoate degradation to catechol (oxic)	step 1 subunit A	Benzoate => cis-1,2-Dihydroxycyclohexa-3,5-diene-1-carboxylate	oxic	EC:1.14.12.10		0
+K05550,EC:1.14.12.10	benB; benzoate/toluate 1,2-dioxygenase subunit beta [EC:1.14.12.10 1.14.12.-] [RN:R05290 R05291 R05428 R05621 R05622 R05665 R08100 R08101 R08108 R08109 R08110]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoic_Acid	Benzoate degradation to catechol (oxic)	step 1 subunit B	Benzoate => cis-1,2-Dihydroxycyclohexa-3,5-diene-1-carboxylate	oxic	EC:1.14.12.10		0
+K05784	benC; benzoate/toluate 1,2-dioxygenasreductase component [EC:1.18.1.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoic_Acid	Benzoate degradation to catechol (oxic)	step 1 subunit C	Benzoate => cis-1,2-Dihydroxycyclohexa-3,5-diene-1-carboxylate	oxic			0
+K05783, EC:1.3.1.25	benD; dihydroxycyclohexadiene carboxylate dehydrogenase [EC:1.3.1.25 1.3.1.-]	Product of: Benzoic_Acid	Benzoate degradation to catechol (oxic)	step 2	cis-1,2-Dihydroxycyclohexa-3,5-diene-1-carboxylate => Catechol	oxic	EC:1.3.1.25		0
+K07824,EC:1.14.14.92	benzoate 4-monooxygenase [EC:1.14.14.92]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoic_Acid	Benzoate degradation to Protocatechuic Acid (oxic)	step 1	Benzoate => 4-hydroxybenzoate	oxic	EC:1.14.14.92		0
+K00481,EC:1.14.13.2	pobA; p-hydroxybenzoate 3-monooxygenase [EC:1.14.13.2]	Non-Polyphenol;Aromatic_Hydrocarbon;4-Hydroxybenzoic_Acid	Benzoate degradation to Protocatechuic Acid (oxic)	step 2	4-hydroxybenzoate => 3,4-dihydroxybenzoate	oxic	EC:1.14.13.2		0
+AA6	AA6 1,4-benzoquinone reductase (EC. 1.6.5.6)	Polyphenols;Polymer	Benzoquinone Reductase (Non-Specific)	step 1	non-specific	oxic	EC. 1.6.5.6		0
+K04110	badA; benzoate-CoA ligase [EC:6.2.1.25]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoic_Acid	Benzoate conversion to Benzoyl-CoA (oxic or anoxic)	step 1	Benzoate => Benzoyl-coA	both	EC:6.2.1.25		0
+K15511	boxA; benzoyl-CoA 2,3-epoxidase subunit A [EC:1.14.13.208]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoyl-CoA	Benzoyl-CoA degradation (oxic)	step 1 subunit A	benzoyl-CoA => 2,3-epoxy-2,3-dihydrobenzoyl-CoA	oxic	EC:1.14.13.208		0
+K15512	boxB; benzoyl-CoA 2,3-epoxidase subunit B [EC:1.14.13.208]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoyl-CoA	Benzoyl-CoA degradation (oxic)	step 1 subunit B	benzoyl-CoA => 2,3-epoxy-2,3-dihydrobenzoyl-CoA	oxic	EC:1.14.13.208		0
+K15513	boxC; benzoyl-CoA-dihydrodiol lyase [EC:4.1.2.44]	Product of: Benzoyl-CoA	Benzoyl-CoA degradation (oxic)	step 2	2,3-epoxy-2,3-dihydrobenzoyl-CoA => (3Z)-6-oxohex-3-enoyl-CoA + formate	oxic	EC:4.1.2.44		0
+K15514	boxD; 3,4-dehydroadipyl-CoA semialdehyde dehydrogenase [EC:1.2.1.77]	Product of: Benzoyl-CoA	Benzoyl-CoA degradation (oxic)	step 3	3,4-didehydroadipyl-CoA semialdehyde => 3,4-didehydroadipyl-CoA	oxic	EC:1.2.1.77		0
+K04114	bcrA; benzoyl-CoA reductase subunit A [EC:1.3.7.8]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoyl-CoA	Benzoyl-CoA Degradation Route 1 (anoxic)	route 1 Step 1 subunit A	Benzoyl-CoA => Cyclohexa-1,5-diene-1-carbonyl-CoA	anoxic	EC:1.3.7.8		0
+K04113	bcrB; benzoyl-CoA reductase subunit B [EC:1.3.7.8]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoyl-CoA	Benzoyl-CoA Degradation Route 1 (anoxic)	route 1 Step 1 subunit B	Benzoyl-CoA => Cyclohexa-1,5-diene-1-carbonyl-CoA	anoxic	EC:1.3.7.8		0
+K04112,EC:1.3.7.8	bcrC; benzoyl-CoA reductase subunit C [EC:1.3.7.8]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoyl-CoA	Benzoyl-CoA Degradation Route 1 (anoxic)	route 1 Step 1 subunit C	Benzoyl-CoA => Cyclohexa-1,5-diene-1-carbonyl-CoA	anoxic	EC:1.3.7.8		0
+K04115	bcrD; benzoyl-CoA reductase subunit D [EC:1.3.7.8]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoyl-CoA	Benzoyl-CoA Degradation Route 1 (anoxic)	route 1 Step 1 subunit D	Benzoyl-CoA => Cyclohexa-1,5-diene-1-carbonyl-CoA	anoxic	EC:1.3.7.8		0
+K07537,EC:4.2.1.100	dch; cyclohexa-1,5-dienecarbonyl-CoA hydratase [EC:4.2.1.100]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 1 (anoxic)	route 1 step 2 	Cyclohexa-1,5-diene-1-carbonyl-CoA => 6-Hydroxycyclohex-1-ene-1-carbonyl-CoA	anoxic	EC:4.2.1.100		0
+K07538,EC:1.1.1.368	had; 6-hydroxycyclohex-1-ene-1-carbonyl-CoA dehydrogenase [EC:1.1.1.368]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 1 (anoxic)	route 1 step 3 	6-Hydroxycyclohex-1-ene-1-carbonyl-CoA => 6-Oxocyclohex-1-ene-1-carbonyl-CoA	anoxic	EC:1.1.1.368		0
+K07539,EC:3.7.1.21	oah; 6-oxocyclohex-1-ene-carbonyl-CoA hydrolase [EC:3.7.1.21]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 1 (anoxic)	route 1 step 4 	6-Oxocyclohex-1-ene-1-carbonyl-CoA => 3-Hydroxypimeloyl-CoA	anoxic	EC:3.7.1.21		0
+K19515	benzoyl-CoA reductase subunit BamB [EC:1.3.-.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoyl-CoA	Benzoyl-CoA Degradation Route 2 (anoxic)	route 2 step 1 subunit B	Benzoyl-CoA => Cyclohexa-1,5-diene-1-carbonyl-CoA	anoxic			0
+K19516	benzoyl-CoA reductase subunit BamC [EC:1.3.-.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzoyl-CoA	Benzoyl-CoA Degradation Route 2 (anoxic)	route 2 step 1 subunit C	Benzoyl-CoA => Cyclohexa-1,5-diene-1-carbonyl-CoA	anoxic			0
+K07537,EC:4.2.1.100	dch; cyclohexa-1,5-dienecarbonyl-CoA hydratase [EC:4.2.1.100]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 2 (anoxic)	route 2 step 2 	Cyclohexa-1,5-diene-1-carbonyl-CoA => 6-Hydroxycyclohex-1-ene-1-carbonyl-CoA	anoxic	EC:4.2.1.100		0
+K07538,EC:1.1.1.368	had; 6-hydroxycyclohex-1-ene-1-carbonyl-CoA dehydrogenase [EC:1.1.1.368]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 2 (anoxic)	route 2 step 3 	6-Hydroxycyclohex-1-ene-1-carbonyl-CoA => 6-Oxocyclohex-1-ene-1-carbonyl-CoA	anoxic	EC:1.1.1.368		0
+K07539,EC:3.7.1.21	oah; 6-oxocyclohex-1-ene-carbonyl-CoA hydrolase [EC:3.7.1.21]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 2 (anoxic)	route 2 step 4 	6-Oxocyclohex-1-ene-1-carbonyl-CoA => 3-Hydroxypimeloyl-CoA	anoxic	EC:3.7.1.21		0
+K19066 	cyclohex-1-ene-1-carbonyl-CoA dehydrogenase [EC:1.3.8.10]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 3 (anoxic)	route 3 step 2	Cyclohex-1-ene-1-carboxyl-CoA => Cyclohexa-1,5-diene-1-carbonyl-CoA	anoxic	EC:1.3.8.10		0
+K07534	badK; cyclohex-1-ene-1-carboxyl-CoA hydratase [EC:4.2.1.-]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 3 (anoxic)	route 3 step 3	Cyclohex-1-ene-1-carboxyl-CoA => 2-Hydroxycyclohexane-1-carboxyl-CoA	anoxic			0
+K07535	badH; 2-hydroxycyclohexanecarboxyl-CoA dehydrogenase [EC:1.1.1.-]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 3 (anoxic)	route 3 step 4	2-Hydroxycyclohexane-1-carboxyl-CoA => 2-Ketocyclohexane-1-carboxyl-CoA	anoxic			0
+K07536	badI; 2-ketocyclohexanecarboxyl-CoA hydrolase [EC:3.1.2.-]	Product of: Benzoyl-CoA	Benzoyl-CoA Degradation Route 3 (anoxic)	route 3 step 5	2-Ketocyclohexane-1-carboxyl-CoA => 6-Carboxyhexanoyl-CoA	anoxic			0
+K08689,EC:1.14.12.18	Biphenyl 2,3-dioxygenase subunit alpha [EC:1.14.12.18]	Non-Polyphenol;Aromatic_Hydrocarbon;Biphenyl	Biphenyl Conversion to Benzoate (oxic)	step 1 subunit A	Biphenyl => cis-2,3-Dihydro-2,3-dihydroxybiphenyl	oxic	EC:1.14.12.18		0
+K15750	biphenyl 2,3-dioxygenase subunit beta [EC:1.14.12.18]	Non-Polyphenol;Aromatic_Hydrocarbon;Biphenyl	Biphenyl Conversion to Benzoate (oxic)	step 1 subunit B	Biphenyl => cis-2,3-Dihydro-2,3-dihydroxybiphenyl	oxic	EC:1.14.12.18		0
+K18087	biphenyl 2,3-dioxygenase ferredoxin component	Non-Polyphenol;Aromatic_Hydrocarbon;Biphenyl	Biphenyl Conversion to Benzoate (oxic)	step 1 subunit C	Biphenyl => cis-2,3-Dihydro-2,3-dihydroxybiphenyl	oxic			0
+K18088	biphenyl 2,3-dioxygenase ferredoxin reductase component [EC:1.18.1.3]	Non-Polyphenol;Aromatic_Hydrocarbon;Biphenyl	Biphenyl Conversion to Benzoate (oxic)	step 1 subunit D	Biphenyl => cis-2,3-Dihydro-2,3-dihydroxybiphenyl	oxic	EC:1.18.1.3		0
+K08690,EC:1.3.1.56	cis-2,3-dihydrobiphenyl-2,3-diol dehydrogenase [EC:1.3.1.56]	Product of: Biphenyl	Biphenyl Conversion to Benzoate (oxic)	step 2	cis-2,3-Dihydro-2,3-dihydroxybiphenyl => 2,3-Dihydroxybiphenyl	oxic	EC:1.3.1.56		0
+K00462,EC:1.13.11.39	biphenyl-2,3-diol 1,2-dioxygenase [EC:1.13.11.39]	Product of: Biphenyl	Biphenyl Conversion to Benzoate (oxic)	step 3	2,3-Dihydroxybiphenyl => 2-Hydroxy-6-oxo-6-phenylhexa-2,4-dienoate	oxic	EC:1.13.11.39		0
+K10222,EC:3.7.1.8	2,6-dioxo-6-phenylhexa-3-enoate hydrolase [EC:3.7.1.8]	Product of: Biphenyl	Biphenyl Conversion to Benzoate (oxic)	step 4	2-Hydroxy-6-oxo-6-phenylhexa-2,4-dienoate + 2-Hydroxy-2,4-pentadienoate + Benzoate	oxic	EC:3.7.1.8		0
+D00018	CarA;hydrocaffeyl-CoA:caffeate CoA transferase	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Caffeic_Acid	Caffeate Respiration (anoxic)	Subunit A	hydrocaffeyl-coA => caffeyl-coA + hydrocaffeate	anoxic	EC:1.3.1.108	gene cluster	0
+D00017	CarB;caffeyl-CoA synthetase 	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Caffeic_Acid	Caffeate Respiration (anoxic)	Subunit B	caffeate => caffeyl-coenzyme A	anoxic	EC:1.3.1.108	gene cluster	1
+D00016,K22430,EC:1.3.1.108	CarC;caffeyl-CoA reductase 	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Caffeic_Acid	Caffeate Respiration (anoxic)	Subunit C	caffeyl-coA => hydrocaffeyl-coA	anoxic	EC:1.3.1.108	gene cluster	0
+D00015,K22431	CarD;electron transfer flavoprotein A	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Caffeic_Acid	Caffeate Respiration (anoxic)	Subunit D	electron transfer	anoxic	EC:1.3.1.108	gene cluster	0
+D00014,K22432	CarE;electron transfer flavoprotein B	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Caffeic_Acid	Caffeate Respiration (anoxic)	Subunit E	electron transfer	anoxic	EC:1.3.1.108	gene cluster	0
+K00446	catechol 2,3 dioxygenase	Polyphenols;Other_polyphenols;Other_polyphenols;Catechol	Catechol Degradation- Meta-Cleavage Route 1 (oxic)	route 1 step 1	catechol => 2-hydroxymuconic semialdehyde	oxic	EC:1.13.11.2		0
+K10217	2-hydroxymuconate semialdehyde dehydrogenase	Product of: Catechol	Catechol Degradation- Meta-Cleavage Route 1 (oxic)	route 2 step 2 	(2Z,4E)-2-hydroxy-6-oxohexa-2,4-dienoate => (2Z,4E)-2-hydroxyhexa-2,4-dienoate	oxic	EC:1.2.1.85		0
+K01821	2-hydroxymuconate tautomerase	Product of: Catechol	Catechol Degradation- Meta-Cleavage Route 1 (oxic)	route 2 step 3 	(2Z,4E)-2-hydroxyhexa-2,4-dienoate => (3E)-2-oxohex-3-enedioate	oxic	EC:5.3.2.6		0
+K18364	2-oxopent-4-enoate hydratase	Product of: Catechol	Catechol Degradation- Meta-Cleavage Route 1 (oxic)	route 2 step 5	(2Z)-2-hydroxypenta-2,4-dienoate => (S)-4-hydroxy-2-oxopentanoate	oxic	EC:4.2.1.132		0
+K18365	4-hydroxy-2-oxovalerate/4-hydroxy-2-oxohexanoate aldolase [EC:4.1.3.39 4.1.3.43]	Product of: Catechol	Catechol Degradation- Meta-Cleavage Route 1 (oxic)	route 2 step 6	4-Hydroxy-2-oxopentanoate => Acetaldehyde + Pyruvate	oxic	EC:4.1.3.39,EC:4.1.3.43		0
+K01617	2-oxo-3-hexenedioate decarboxylase	Product of: Catechol	Catechol Degradation- Meta-Cleavage Route 2 (oxic)	route 2 step 4 	(3E)-2-oxohex-3-enedioate => (2Z)-2-hydroxypenta-2,4-dienoate	oxic	EC:4.1.1.77		0
+K07104	catechol 2,3 dioxygenase	Polyphenols;Other_polyphenols;Other_polyphenols;Catechol	Catechol Degradation- Meta-Cleavage Route 2 (oxic)	route 2 step 1	catechol => 2-hydroxymuconic semialdehyde	oxic	EC:1.13.11.2		0
+K10216	2-hydroxymuconic semialdehyde hydrolase	Product of: Catechol	Catechol Degradation- Meta-Cleavage Route 2 (oxic)	route 2 step 2 	2-hydroxymuconic semialdehyde => 2-oxo-4-enoate	oxic	EC:3.7.1.9		0
+K02554	2-oxo-4-pentenoate hydratase	Product of: Catechol	Catechol Degradation- Meta-Cleavage Route 2 (oxic)	route 2 step 3 	2-oxo-4-enoate => 4-hydroxy-2-oxovalerate	oxic	EC:4.2.1.80		0
+K01666	4-hydroxy-2-oxovalerate aldolase	Product of: Catechol	Catechol Degradation- Meta-Cleavage Route 2 (oxic)	route 2 step 4 	4-hydroxy-2-oxovalerate => pyruvate + acetaldehyde	oxic	EC:4.1.3.39		0
+K03381, EC:1.13.11.1	catechol 1,2-dioxygenase [EC:1.13.11.1]	Polyphenols;Other_polyphenols;Other_polyphenols;Catechol	Catechol Degradation- Ortho Cleavage (oxic)	Step 1	Catechol => cis,cis-Muconate	oxic	EC:1.13.11.1		0
+K01856, EC:5.5.1.1	muconate cycloisomerase [EC:5.5.1.1]	Product of: Catechol	Catechol Degradation- Ortho Cleavage (oxic)	Step 2	cis,cis-Muconate => (+)-Muconolactone	oxic	EC:5.5.1.1		0
+K03464, EC:5.3.3.4	muconolactone D-isomerase [EC:5.3.3.4]	Product of: Catechol	Catechol Degradation- Ortho Cleavage (oxic)	Step 3	(+)-Muconolactone => 3-Oxoadipate enol-lactone	oxic	EC:5.3.3.4		0
+K01055, EC:3.1.1.24	3-oxoadipate enol-lactonase [EC:3.1.1.24]	Product of: Catechol	Catechol Degradation- Ortho Cleavage (oxic)	Step 4	3-Oxoadipate enol-lactone => 3-Oxoadipate	oxic	EC:3.1.1.24		0
+D00034,EC:3.1.1.42	ChlE;chlorogenic acid esterase	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Chlorogenic_acid	Chlorogenic Acid Cleavage (oxic or anoxic)	step 1	chlorogenate => caffeic acid + quinate	both	EC:3.1.1.42		0
+D00026,EC:1.1.1.194	CalA;coniferyl alcohol dehydrogenase	Polyphenols;Other_polyphenols;Methoxyphenols;Coniferyl_alcohol	Coniferyl Alcohol Conversion to Ferulic Acid (oxic)	Step 1	coniferyl alcohol => coniferyl aldehyde	oxic	EC:1.1.1.194		0
+D00037	CalB;coniferyl aldehyde dehydrogenase	Polyphenols;Other_polyphenols;Methoxyphenols;Coniferyl_aldehyde	Coniferyl Alcohol Conversion to Ferulic Acid (oxic)	Step 2	coniferyl aldehyde => ferulic acid	oxic			0
+D00039	sam5;flavonoid hydroxylase	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Coumaric_acid	Coumaric Acid Conversion (oxic)	step 1	coumaric acid => caffeic acid	oxic			0
+K10619,EC:1.14.12.25	p-cumate 2,3-dioxygenase subunit alpha [EC:1.14.12.25]	Product of: Cumate	Cumic Acid Degradation (oxic)	Step 1 subunit A	p-Cumate => cis-2,3-Dihydroxy-2,3-dihydro-p-cumate	oxic	EC:1.14.12.25		0
+K16303	p-cumate 2,3-dioxygenase subunit beta [EC:1.14.12.25]	Product of: Cumate	Cumic Acid Degradation (oxic)	Step 1 subunit B	p-Cumate => cis-2,3-Dihydroxy-2,3-dihydro-p-cumate	oxic	EC:1.14.12.25		0
+K16304	p-cumate 2,3-dioxygenase ferredoxin component	Product of: Cumate	Cumic Acid Degradation (oxic)	Step 1 subunit C	p-Cumate => cis-2,3-Dihydroxy-2,3-dihydro-p-cumate	oxic			0
+K18227	p-cumate 2,3-dioxygenase ferredoxin reductase component [EC:1.18.1.3]	Product of: Cumate	Cumic Acid Degradation (oxic)	Step 1 subunit D	p-Cumate => cis-2,3-Dihydroxy-2,3-dihydro-p-cumate	oxic	EC:1.18.1.3		0
+K10620,EC:1.3.1.58	2,3-dihydroxy-2,3-dihydro-p-cumate dehydrogenase [EC:1.3.1.58]	Product of: Cumate	Cumic Acid Degradation (oxic)	step 2	cis-2,3-Dihydroxy-2,3-dihydro-p-cumate => 2,3-Dihydroxy-p-cumate	oxic	EC:1.3.1.58		0
+K10621,EC:1.13.11.14	2,3-dihydroxy-p-cumate/2,3-dihydroxybenzoate 3,4-dioxygenase [EC:1.13.11.- 1.13.11.14]	Product of: Cumate	Cumic Acid Degradation (oxic)	step 3	2,3-Dihydroxy-p-cumate => 2-Hydroxy-3-carboxy-6-oxo-7-methylocta-2,4-dienoate	oxic	EC:1.13.11.14		0
+K10622	HCOMODA/2-hydroxy-3-carboxy-muconic semialdehyde decarboxylase [EC:4.1.1.-]	Product of: Cumate	Cumic Acid Degradation (oxic)	step 4	2-Hydroxy-3-carboxy-6-oxo-7-methylocta-2,4-dienoate => 2-Hydroxy-6-oxo-7-methylocta-2,4-dienoate	oxic			0
+K10623	HOMODA hydrolase [EC:3.7.1.-]	Product of: Cumate	Cumic Acid Degradation (oxic)	step 5	2-Hydroxy-6-oxo-7-methylocta-2,4-dienoate => Methylpropanoate + cis-2-hydroxy-penta-2,4-dienoate	oxic			0
+D00019	CurA; curcumin/dihydrocurcumin reductase	Polyphenols;Other_polyphenols;Curcuminoids;Curcumin	Curcumin Conversion	step 1	curcumin => tetrahydrocurcumin	anoxic			0
+K10616,EC:1.14.15.25	p-cymene methyl-monooxygenase [EC:1.14.15.25]	Non-Polyphenol;Aromatic_Hydrocarbon;Terpenoid;p-cymene	Cymene conversion to Cumic acid (oxic)	step 1 subunit A	p-Cymene => p-Cumic alcohol	oxic	EC:1.14.15.25		0
+K18293	p-cymene methyl-monooxygenase electron transfer component [EC:1.18.1.3]	Product of: Cymene	Cymene conversion to Cumic acid (oxic)	step 1 subunit B	p-Cymene => p-Cumic alcohol	oxic	EC:1.18.1.3		0
+K10617	p-cumic alcohol dehydrogenase	Product of: Cymene	Cymene conversion to Cumic acid (oxic)	step 2	p-Cumic alcohol => cuminaldehyde	oxic			0
+K10618	p-cumic aldehyde dehydrogenase	Non-Polyphenol;Aromatic_Hydrocarbon;Terpenoid;p-cumate	Cymene conversion to Cumic acid (oxic)	step 3	cuminaldehyde => p-Cumate	oxic			0
+D00029	PhcD;(-)-dehydrodiconiferyl acid dehydrogenase/hydroxylase	Polyphenols;Lignans;Lignans;Dehydroconiferyl_alcohol	Dehydroconiferyl alcohol conversion (oxic or anoxic)	Step 1 enzyme (-)	DCA-C => DCA-CL => DCA-CC	both			0
+D00028	PhcC;(+)-dehydrodiconiferyl acid dehydrogenase	Product of: Dehydroconiferyl_alcohol	Dehydroconiferyl alcohol conversion (oxic or anoxic)	Step 1 enzyme (+)	DCA-C => DCA-CL => DCA-CC	both			0
+D00031	PhcG;(-)-DCA-CC decarboxylase	Product of: Dehydroconiferyl_alcohol	Dehydroconiferyl alcohol conversion (oxic or anoxic)	Step 2 enzyme (-)	DCA-CC => DCA-S	both			0
+D00030	PhcF;(+)-DCA-CC decarboxylase	Product of: Dehydroconiferyl_alcohol	Dehydroconiferyl alcohol conversion (oxic or anoxic)	Step 2 enzyme (+)	DCA-CC => DCA-S	both			0
+D00007	LSD;Iignostilbene-e,y-dioxygenase	Product of: Dehydroconiferyl_alcohol	Dehydroconiferyl alcohol conversion (oxic or anoxic)	Step 3	DCA-S => 5-formylferulate + vanillin	both			0
+K10700,EC:1.17.99.2	ethylbenzene hydroxylase subunit alpha [EC:1.17.99.2]	Non-Polyphenol;Aromatic_Hydrocarbon;Ethylbenzene	Ethylbenzene Conversion to Benzoyl-CoA (anoxic)	step 1 subunit A	Ethylbenzene => (S)-1-Phenylethanol	anoxic	EC:1.17.99.2		0
+K17048	ethylbenzene hydroxylase subunit beta	Product of: Ethylbenzene	Ethylbenzene Conversion to Benzoyl-CoA (anoxic)	step 1 subunit B	Ethylbenzene => (S)-1-Phenylethanol	anoxic			0
+K17049	ethylbenzene hydroxylase subunit gamma	Product of: Ethylbenzene	Ethylbenzene Conversion to Benzoyl-CoA (anoxic)	step 1 subunit C	Ethylbenzene => (S)-1-Phenylethanol	anoxic			0
+K14746,EC:1.1.1.311	(S)-1-phenylethanol dehydrogenase [EC:1.1.1.311]	Product of: Ethylbenzene	Ethylbenzene Conversion to Benzoyl-CoA (anoxic)	step 2	(S)-1-Phenylethanol => Acetophenone	anoxic	EC:1.1.1.311		0
+K10701,EC:6.4.1.8	acetophenone carboxylase [EC:6.4.1.8]	Product of: Ethylbenzene	Ethylbenzene Conversion to Benzoyl-CoA (anoxic)	step 3	Acetophenone => 3-Oxo-3-phenylpropanoate	anoxic	EC:6.4.1.8		0
+K14747	benzoylacetate-CoA ligase [EC:6.2.1.-]	Product of: Ethylbenzene	Ethylbenzene Conversion to Benzoyl-CoA (anoxic)	step 4	3-Oxo-3-phenylpropanoate => Benzoylacetyl-CoA	anoxic			0
+K14748	ethylbenzene dioxygenase subunit alpha [EC:1.14.12.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Ethylbenzene	Ethylbenzene Degradation (oxic)	step 1 subunit A	Ethylbenzene => cis-1,2-Dihydro-3-ethylcatechol	oxic			0
+K14749	ethylbenzene dioxygenase subunit beta [EC:1.14.12.-]	Product of: Ethylbenzene	Ethylbenzene Degradation (oxic)	step 1 subunit B	Ethylbenzene => cis-1,2-Dihydro-3-ethylcatechol	oxic			0
+K14750	ethylbenzene dioxygenase ferredoxin component	Product of: Ethylbenzene	Ethylbenzene Degradation (oxic)	step 1 subunit C	Ethylbenzene => cis-1,2-Dihydro-3-ethylcatechol	oxic			0
+EC:1.3.1.66	cis-1,2-Dihydro-3-ethylcatechol:NAD+ oxidoreductase	Product of: Ethylbenzene	Ethylbenzene Degradation (oxic)	step 2	cis-1,2-Dihydro-3-ethylcatechol => 3-Ethylcatechol	oxic	EC:1.3.1.66		0
+K14751	2,3-dihydroxyethylbenzene 1,2-dioxygenase [EC:1.13.11.-]	Other_polyphenols;Alkylphenols;3-Ethylcatechol	Ethylbenzene Degradation (oxic)	step 3	3-Ethylcatechol => 2-Hydroxy-6-oxo-octa-2,4-dienoate	oxic			0
+K18092	2-hydroxy-6-oxo-octa-2,4-dienoate hydrolase [EC:3.7.1.-]	Product of: 3-Ethylcatechol	Ethylbenzene Degradation (oxic)	step 4	2-Hydroxy-6-oxo-octa-2,4-dienoate => 2-Hydroxy-2,4-pentadienoate + Propanoate	oxic			0
+D00024	EhyA;eugenol hydroxylase subunit A	Polyphenols;Other_polyphenols;Hydroxyphenylpropenes;Eugenol	Eugenol Conversion to Coniferyl Alcohol (oxic)	Step 1 Subunit A	eugenol => coniferyl alcohol	oxic			0
+D00025	EhyB;eugenol hydroxylase subunit B	Polyphenols;Other_polyphenols;Hydroxyphenylpropenes;Eugenol	Eugenol Conversion to Coniferyl Alcohol (oxic)	Step 1 Subunit B	eugenol => coniferyl alcohol	oxic			0
+D00038,K12508,EC:6.2.1.34	FCS;feruloyl-CoA synthetase	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Ferulic_acid	Ferulic Acid Conversion to Vanillin (oxic)	Step 1	ferulic acid => feruloyl-coA	oxic	EC:6.2.1.34		0
+K18383 	feruloyl-CoA hydratase/lyase	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Ferulic_acid	Ferulic Acid Conversion to Vanillin (oxic)	Step 2	feruloyl-CoA => vanillin	oxic	EC:4.1.2.61		0
+D00039	sam5;flavonoid hydroxylase	Polyphenols;Flavonoids;Flavanones;	Flavanone Degradation (oxic)	step 1	flavanones => hydroxyflavanones	oxic			0
+D00039	sam5;flavonoid hydroxylase	Polyphenols;Flavonoids;Flavones;	Flavone degradation (oxic)	step 1	flavones => hydroxyflavones, luteolin => hypolaetin	oxic			0
+D00009	FLR; Flavone/flavonol reductase 	Polyphenols;Flavonoids;Flavones;	Flavone degradation to phloroglucinol (anoxic)	step 1	flavones => flavanones	anoxic			0
+D00003,EC:5.5.1.6	CHI; Chalcone isomerase	Polyphenols;Flavonoids;Flavanones;	Flavone degradation to phloroglucinol (anoxic)	step 2a	flavanones <=> chalcones	anoxic	EC:5.5.1.6		0
+D00001	FCR; Flavanone/flavanonol-cleaving reductase	Polyphenols;Flavonoids;Flavanones;	Flavone degradation to phloroglucinol (anoxic)	step 2b	flavanones => dihydrochalcones	anoxic			0
+D00006,K22906,EC:3.7.1.4	PHY; Phloretin hydrolase [EC:3.7.1.4]	Polyphenols;Flavonoids;Dihydrochalcone;	Flavone degradation to phloroglucinol (anoxic)	step 3	dihydrochalcone => phloroglucinol + 3-(4-hydroxyphenyl)propionic acid	anoxic	EC:3.7.1.4	sometimes located adjacent to CHI	0
+D00009	FLR; Flavone/flavonol reductase 	Polyphenols;Flavonoids;Flavonols;	Flavonol degradation to phloroglucinol (anoxic)	step 1	flavonols => flavanonols	anoxic			0
+D00003,EC:5.5.1.6	CHI; Chalcone isomerase	Polyphenols;Flavonoids;Flavanonols;	Flavonol degradation to phloroglucinol (anoxic)	step 2a	flavanonols => auronols	anoxic	EC:5.5.1.6		0
+D00001	FCR; Flavanone/flavanonol-cleaving reductase	Polyphenols;Flavonoids;Flavanonols;	Flavonol degradation to phloroglucinol (anoxic)	step 2b	flavanonols => hydroxydihydrochalcones	anoxic			0
+D00006,K22906,EC:3.7.1.4	PHY; Phloretin hydrolase [EC:3.7.1.4]	Polyphenols;Flavonoids;Hydroxydihydrochalcones;	Flavonol degradation to phloroglucinol (anoxic)	step 3	hydroxydihydrochalcones => phloroglucinol + caffeic acid	anoxic	EC:3.7.1.4	sometimes located adjacent to CHI	0
+K22959	lpdB;gallate decarboxylase subunit B	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Gallic_acid	Gallate Conversion to Pyrogallol (anoxic)	step 1 subunit B	gallate => pyrogallol	anoxic	EC:4.1.1.59		0
+K22958	lpdC;gallate decarboxylase subunit C	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Gallic_acid	Gallate Conversion to Pyrogallol (anoxic)	step 1 subunit C	gallate => pyrogallol	anoxic	EC:4.1.1.59		0
+K22960	lpdD;gallate decarboxylase subunit D	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Gallic_acid	Gallate Conversion to Pyrogallol (anoxic)	step 1 subunit D	gallate => pyrogallol	anoxic	EC:4.1.1.59		0
+K04099	GalD;gallate dioxygenase	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Gallic_acid	Gallate degradation (oxic)	step 1	gallate => (1E)-4-oxobut-1-ene-1,2,4-tricarboxylate	oxic	EC:1.13.11.57	feeds to protocatechuate meta-cleavage	0
+K00450	GenD;gentisate 1,2-dioxygenase	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Gentisic_acid	Gentisic Acid degradation Route 1 (oxic)	route 1 step 1	gentisate => 3-maleylpyruvate	oxic	EC:1.13.11.4		0
+K20758	HbzF;maleylpyruvate hydrolase	Product of: Gentisic_Acid	Gentisic Acid degradation Route 1 (oxic)	route 1 step 2	3-maleylpyruvate => pyruvate	oxic	EC:3.7.1.23		0
+K00450	GenD;gentisate 1,2-dioxygenase	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Gentisic_acid	Gentisic Acid degradation Route 2 (oxic)	route 2 step 1	gentisate => 3-maleylpyruvate	oxic	EC:1.13.11.4		0
+K01801	NagL;maleylpyruvate isomerase	Product of: Gentisic_Acid	Gentisic Acid degradation Route 2 (oxic)	route 2 step 2	3-maleylpyruvate => 3-fumarylpyruvate	oxic	EC:5.2.1.4		0
+K16165	NagK;fumarylpyruvate hydrolase	Product of: Gentisic_Acid	Gentisic Acid degradation Route 2 (oxic)	route 2 step 3	3-fumarylpyruvate => fumarate, pyruvate	oxic	EC:3.7.1.20		0
+K00451	HmgA;homogentisate 1,2-dioxygenase	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Homoprotogentisic_Acid	Homogentisic Acid degradation (oxic)	step 1	homogentisate => 4-maleylacetoacetate	oxic	EC:1.13.11.5		0
+K01800	MaiA;maleylacetoacetate isomerase	Product of: Homogentisic_Acid	Homogentisic Acid degradation (oxic)	step 2	4-maleylacetoacetate => 4-fumarylacetoacetate	oxic	EC:5.2.1.2		0
+K01555	FahA;fumarylacetoacetate hydrolase	Product of: Homogentisic_Acid	Homogentisic Acid degradation (oxic)	step 3	4-fumarylacetoacetate => fumarate, acetoacetate	oxic	EC:3.7.1.2		0
+K00455,EC:1.13.11.5	hpad;3,4-dihydroxyphenylacetate 2,3-dioxygenase [EC:1.13.11.15]	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Homoprotocatechuic_Acid	Homoprotocatechuic Acid degradation (oxic)	step 1	3,4-dihydroxyphenylacetate => 2-Hydroxy-5-carboxymethylmuconate semialdehyde	oxic	EC:1.13.11.15		0
+K00151,EC:1.2.1.60	hpaE; 5-carboxymethyl-2-hydroxymuconic-semialdehyde dehydrogenase [EC:1.2.1.60]	Product of: Homoprotocatechuic_Acid	Homoprotocatechuic Acid degradation (oxic)	step 2 a	2-Hydroxy-5-carboxymethylmuconate semialdehyde <=> 5-Carboxymethyl-2-hydroxymuconate	oxic	EC:1.2.1.60		0
+K10219,EC:1.1.1.312	ligB; 2-hydroxy-4-carboxymuconate semialdehyde hemiacetal dehydrogenase [EC:1.1.1.312]	Product of: Homoprotocatechuic_Acid	Homoprotocatechuic Acid degradation (oxic)	step 2 b	2-Hydroxy-5-carboxymethylmuconate semialdehyde <=> 5-Carboxymethyl-2-hydroxymuconate	oxic	EC:1.1.1.312		0
+K01826,EC:5.3.3.10	hpaF; 5-carboxymethyl-2-hydroxymuconate isomerase [EC:5.3.3.10]	Product of: Homoprotocatechuic_Acid	Homoprotocatechuic Acid degradation (oxic)	step 3	5-Carboxymethyl-2-hydroxymuconate <=> 5-Carboxy-2-oxohept-3-enedioate	oxic	EC:5.3.3.10		0
+K05921,EC:4.1.1.68	hpaG; 5-oxopent-3-ene-1,2,5-tricarboxylate decarboxylase / 2-hydroxyhepta-2,4-diene-1,7-dioate isomerase [EC:4.1.1.68 5.3.3.-]	Product of: Homoprotocatechuic_Acid	Homoprotocatechuic Acid degradation (oxic)	step 4	5-Carboxy-2-oxohept-3-enedioate <=> 2-Oxohept-3-enedioate	oxic	EC:4.1.1.68		0
+K02509	2-oxo-hept-3-ene-1,7-dioate hydratase	Product of: Homoprotocatechuic_Acid	Homoprotocatechuic Acid degradation (oxic)	step 5	2-oxohept-3-enedioate => 2,4-dihydroxyhept-2-enedioate	oxic	EC:4.2.1.-		0
+K02510	4-hydroxy-2-oxoheptanedioate aldolase	Product of: Homoprotocatechuic_Acid	Homoprotocatechuic Acid degradation (oxic)	step 6	2,4-dihydroxyhept-2-enedioate => succinate semialdehyde	oxic	EC:4.1.2.52		0
+K00135	succinate-semialdehyde dehydrogenase	Product of: Homoprotocatechuic_Acid	Homoprotocatechuic Acid degradation (oxic)	step 7	succinate semialdehyde => succinate	oxic	EC:1.2.1.16		0
+K10759,EC:3.1.1.20	tannin feruloyl esterase	Polyphenols;Hydrolyzable_Tannins;;;	Hydrolyzable Tannin Depolymerization (oxic or anoxic)	step 1	ellagitannin => ellagic acid	both	EC:3.1.1.20	extracellular	0
+D00027,EC:1.13.11.88,K23363	IEM;isoeugenol monooxygenase	Polyphenols;Other_polyphenols;Hydroxyphenylpropenes;Isoeugenol	Isoeugenol conversion to vanillin (oxic)	step 1	isoeugenol => vanillin	oxic	EC:1.13.11.88		0
+D00002	DZR;daidzein reductase	Polyphenols;Flavonoids;Isoflavonoids;	Isoflavonoid conversion (anoxic)	step 1	daidzein => dihydrodaidzein, genistein => dihydrogenistein	anoxic		sometimes encoded in gene cluster	0
+D00022	DDRC;dihydrodaidzein racemase	Polyphenols;Flavonoids;Isoflavonoids;	Isoflavonoid conversion (anoxic)	step 2a	(R)-dihydrodaidzein <=> (S)-dihydrodaidzein	anoxic		sometimes encoded in gene cluster	0
+D00005	DDR;dihydrodaidzein reductase	Polyphenols;Flavonoids;Isoflavonoids;	Isoflavonoid conversion (anoxic)	step 2b	dihydrodaidzein => tetrahydrodaidzein, dihydrogenistein => tetrahydrogenistein	anoxic		sometimes encoded in gene cluster	0
+D00004	TDR;tetrahydrodaidzein reductase	Polyphenols;Flavonoids;Isoflavonoids;	Isoflavonoid conversion (anoxic)	step 3	tetrahydrodaidzein => equol, tetrahydrogenistein => 5-hydroxy-equol	anoxic		sometimes encoded in gene cluster	0
+D00039	sam5;flavonoid hydroxylase	Polyphenols;Flavonoids;Isoflavonoids;	Isoflavonoid degradation (oxic)	step 1	isoflavones => hydroxyisoflavones	oxic			0
+K09252,EC:3.1.1.73	feruloyl esterase	Polyphenols;Phenolic_acids;Hydroxycinnamic_acids;Ferulic_acid	lignocellulose depolymerization (oxic or anoxic)	Step 1	feruloyl-polysaccharide => ferulic acid + polysaccharide	both	EC:3.1.1.73		0
+K03380	phenol 2-monooxygenase	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	m-cresol conversion to 3-methylcatechol (oxic)	step 1	3-Cresol => 2,3-Dihydroxytoluene	oxic	EC:1.14.13.7		0
+K05549, EC:1.14.12.10	benzoate/toluate 1,2-dioxygenase subunit alpha [EC:1.14.12.10 1.14.12.-] [RN:R05290 R05291 R05428 R05621 R05622 R05665 R08100 R08101 R08108 R08109 R08110]	Non-Polyphenol;Aromatic_Hydrocarbon;m-methylbenzoic_Acid	m-methylbenzoic acid degradation to 3-methylcatechol (oxic)	step 1 subunit A	m-Methylbenzoate => 1,6-Dihydroxy-5-methylcyclohexa-2,4-dienecarboxylate	oxic	EC:1.14.12.10		0
+K05550,EC:1.14.12.10	benzoate/toluate 1,2-dioxygenase subunit beta [EC:1.14.12.10 1.14.12.-] [RN:R05290 R05291 R05428 R05621 R05622 R05665 R08100 R08101 R08108 R08109 R08110]	Non-Polyphenol;Aromatic_Hydrocarbon;m-methylbenzoic_Acid	m-methylbenzoic acid degradation to 3-methylcatechol (oxic)	step 1 subunit B	m-Methylbenzoate => 1,6-Dihydroxy-5-methylcyclohexa-2,4-dienecarboxylate	oxic	EC:1.14.12.10		0
+K05784	benzoate/toluate 1,2-dioxygenasreductase component [EC:1.18.1.-]	Non-Polyphenol;Aromatic_Hydrocarbon;m-methylbenzoic_Acid	m-methylbenzoic acid degradation to 3-methylcatechol (oxic)	step 1 subunit C	m-Methylbenzoate => 1,6-Dihydroxy-5-methylcyclohexa-2,4-dienecarboxylate	oxic			0
+K05783, EC:1.3.1.25	dihydroxycyclohexadiene carboxylate dehydrogenase [EC:1.3.1.25 1.3.1.-]	Product of: m-methylbenzoic_acid	m-methylbenzoic acid degradation to 3-methylcatechol (oxic)	step 2	1,6-Dihydroxy-5-methylcyclohexa-2,4-dienecarboxylate => 3-Methylcatechol	oxic	EC:1.3.1.25		0
+K15757, EC:1.14.15.26	toluene methyl-monooxygenase [EC:1.14.15.26] [RN:R02550 R05288 R05442 R05443]	Non-Polyphenol;Aromatic_Hydrocarbon;m-Xylene	m-xylene conversion to m-Toluate (oxic)	step 1 subunit A	m-Xylene => 3-Methylbenzyl alcohol	oxic	EC:1.14.15.26		0
+K15758,EC:1.18.1.3	toluene methyl-monooxygenase electron transfer component [EC:1.18.1.3] [RN:R02550 R05288 R05442 R05443]	Non-Polyphenol;Aromatic_Hydrocarbon;m-Xylene	m-xylene conversion to m-Toluate (oxic)	step 1 subunit B	m-Xylene => 3-Methylbenzyl alcohol	oxic	EC:1.18.1.3		0
+K00055,EC:1.1.1.90,AA3_2	aryl-alcohol dehydrogenase [EC:1.1.1.90] [RN:R01763 R02611 R04304 R05282 R05347 R05348]	Product of: m-Xylene	m-xylene conversion to m-Toluate (oxic)	step 2	3-Methylbenzyl alcohol => 3-Methylbenzaldehyde 	oxic	EC:1.1.1.90		0
+K00141, EC:1.2.1.28	benzaldehyde dehydrogenase (NAD) [EC:1.2.1.28] [RN:R01293 R01419 R05289 R05663 R05664 R07667	Product of: m-Xylene	m-xylene conversion to m-Toluate (oxic)	step 3	3-Methylbenzaldehyde => m-Methylbenzoate	oxic	EC:1.2.1.28		0
+K01781	mandelate racemase	Non-Polyphenol;Aromatic_Hydrocarbon;Mandelic_Acid	Mandelic acid conversion to benzaldehyde (oxic)	step 1	(R)-mandelate => (S)-mandelate	oxic	EC:5.1.2.2		0
+K15054	(S)-mandelate dehydrogenase	Product of: Mandelic_Acid	Mandelic acid conversion to benzaldehyde (oxic)	step 2	(s)-mandelate => phenylglyoxylate	oxic	EC:1.1.99.31		0
+K01576	benzoylformate decarboxylase	Product of: Mandelic_Acid	Mandelic acid conversion to benzaldehyde (oxic)	step 3	phenylglyoxylate => benzaldehyde	oxic	EC:4.1.1.7	feeds to benzaldehyde degradation	0
+K14579	nahA; naphthalene 1,2-dioxygenase subunit alpha [EC:1.14.12.12 1.14.12.23 1.14.12.24]	Non-Polyphenol;Aromatic_Hydrocarbon;Naphthalene	Napthalene Conversion to Salicylaldehyde (oxic)	step 1 subunit A	Naphthalene => cis-1,2-Dihydronaphthalene-1,2-diol	oxic	EC:1.14.12.12,EC:1.14.12.23,EC:1.14.12.24		0
+K14580	nahA; naphthalene 1,2-dioxygenase subunit beta [EC:1.14.12.12 1.14.12.23 1.14.12.24]	Non-Polyphenol;Aromatic_Hydrocarbon;Naphthalene	Napthalene Conversion to Salicylaldehyde (oxic)	step 1 subunit B	Naphthalene => cis-1,2-Dihydronaphthalene-1,2-diol	oxic	EC:1.14.12.12,EC:1.14.12.23,EC:1.14.12.24		0
+K14578	nahA; naphthalene 1,2-dioxygenase ferredoxin component	Non-Polyphenol;Aromatic_Hydrocarbon;Naphthalene	Napthalene Conversion to Salicylaldehyde (oxic)	step 1 subunit C	Naphthalene => cis-1,2-Dihydronaphthalene-1,2-diol	oxic			0
+K14581	nahA; naphthalene 1,2-dioxygenase ferredoxin reductase component [EC:1.18.1.7]	Non-Polyphenol;Aromatic_Hydrocarbon;Naphthalene	Napthalene Conversion to Salicylaldehyde (oxic)	step 1 subunit D	Naphthalene => cis-1,2-Dihydronaphthalene-1,2-diol	oxic			0
+K14582	nahB; cis-1,2-dihydro-1,2-dihydroxynaphthalene/dibenzothiophene dihydrodiol dehydrogenase [EC:1.3.1.29 1.3.1.60]	Product of: Naphthalene	Napthalene Conversion to Salicylaldehyde (oxic)	step 2	cis-1,2-Dihydronaphthalene-1,2-diol => Naphthalene-1,2-diol	oxic	EC:1.3.1.29,EC:1.3.1.60		0
+K14583	nahC; 1,2-dihydroxynaphthalene dioxygenase [EC:1.13.11.56]	Product of: Naphthalene	Napthalene Conversion to Salicylaldehyde (oxic)	step 3	Naphthalene-1,2-diol => 2-Hydroxychromene-2-carboxylate	oxic	EC:1.13.11.56		0
+K14584	nahD; 2-hydroxychromene-2-carboxylate isomerase [EC:5.99.1.4]	Product of: Naphthalene	Napthalene Conversion to Salicylaldehyde (oxic)	step 4	2-Hydroxychromene-2-carboxylate => trans-o-Hydroxybenzylidenepyruvate	oxic	EC:5.99.1.4		0
+K14585	nahE; trans-o-hydroxybenzylidenepyruvate hydratase-aldolase [EC:4.1.2.45]	Product of: Naphthalene	Napthalene Conversion to Salicylaldehyde (oxic)	step 5	trans-o-Hydroxybenzylidenepyruvate => Salicylaldehyde + Pyruvate	oxic	EC:4.1.2.45		0
+D00035	FdeE;naringenin hydroxylase	Polyphenols;Flavonoids;Flavanones;Naringenin	Naringenin Degradation (oxic)	step 1	naringenin =>  8-hydroxynaringenin	oxic			0
+D00036	FdeC;naringenin dioxygenase	Polyphenols;Flavonoids;Flavanones;8-hydroxynaringenin	Naringenin Degradation (oxic)	step 2	8-hydroxynaringenin => ((2E,4E)-2,4-dihydroxy-4-[6-(4-hydroxyphenyl)-2,4-dioxodihydro-2H-pyran-3(4H)-ylidene]but-2-enoic acid)	oxic			0
+K16249	dmpK; phenol hydroxylase P0 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;O-Cresol	O-Cresol Conversion to 2,3-Dihydroxytoluene (oxic)	subunit 0	O-Cresol => 2,3-Dihydroxytoluene	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16243	dmpL; Phenol hydroxylase P1 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;O-Cresol	O-Cresol Conversion to 2,3-Dihydroxytoluene (oxic)	subunit 1	O-Cresol => 2,3-Dihydroxytoluene	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16244	dmpM; phenol hydroxylase P2 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;O-Cresol	O-Cresol Conversion to 2,3-Dihydroxytoluene (oxic)	subunit 2	O-Cresol => 2,3-Dihydroxytoluene	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16242	dmpN; phenol hydroxylase P3 protein [EC:1.14.13.-] [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;O-Cresol	O-Cresol Conversion to 2,3-Dihydroxytoluene (oxic)	subunit 3	O-Cresol => 2,3-Dihydroxytoluene	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16245	dmpO; phenol hydroxylase P4 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;O-Cresol	O-Cresol Conversion to 2,3-Dihydroxytoluene (oxic)	subunit 4	O-Cresol => 2,3-Dihydroxytoluene	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16246	dmpP; phenol hydroxylase P5 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;O-Cresol	O-Cresol Conversion to 2,3-Dihydroxytoluene (oxic)	subunit 5	O-Cresol => 2,3-Dihydroxytoluene	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K05549, EC:1.14.12.10	benzoate/toluate 1,2-dioxygenase subunit alpha [EC:1.14.12.10 1.14.12.-] [RN:R05290 R05291 R05428 R05621 R05622 R05665 R08100 R08101 R08108 R08109 R08110]	Non-Polyphenol;Aromatic_Hydrocarbon;O-Toluic_acid	O-Toluate degradation to 3-methylcatechol (oxic)	step 1 subunit A	o-Toluate => 1,2-Dihydroxy-6-methylcyclohexa-3,5-dienecarboxylate	oxic	EC:1.14.12.10		0
+K05550,EC:1.14.12.10	benzoate/toluate 1,2-dioxygenase subunit beta [EC:1.14.12.10 1.14.12.-] [RN:R05290 R05291 R05428 R05621 R05622 R05665 R08100 R08101 R08108 R08109 R08110]	Non-Polyphenol;Aromatic_Hydrocarbon;O-Toluic_acid	O-Toluate degradation to 3-methylcatechol (oxic)	step 1 subunit B	o-Toluate => 1,2-Dihydroxy-6-methylcyclohexa-3,5-dienecarboxylate	oxic	EC:1.14.12.10		0
+K05784	benzoate/toluate 1,2-dioxygenasreductase component [EC:1.18.1.-]	Non-Polyphenol;Aromatic_Hydrocarbon;O-Toluic_acid	O-Toluate degradation to 3-methylcatechol (oxic)	step 1 subunit C	o-Toluate => 1,2-Dihydroxy-6-methylcyclohexa-3,5-dienecarboxylate	oxic			0
+K05783, EC:1.3.1.25	dihydroxycyclohexadiene carboxylate dehydrogenase [EC:1.3.1.25 1.3.1.-]	Product of: O-Toluic_Acid	O-Toluate degradation to 3-methylcatechol (oxic)	step 2	1,2-Dihydroxy-6-methylcyclohexa-3,5-dienecarboxylate => 3-Methylcatechol	oxic	EC:1.3.1.25		0
+K15757, EC:1.14.15.26	toluene methyl-monooxygenase [EC:1.14.15.26] [RN:R02550 R05288 R05442 R05443]	Non-Polyphenol;Aromatic_Hydrocarbon;o-Xylene	o-xylene conversion to o-Toluate (oxic)	step 1 subunit A	o-Xylene => 2-Methylbenzyl alcohol	oxic	EC:1.14.15.26		0
+K15758,EC:1.18.1.3	toluene methyl-monooxygenase electron transfer component [EC:1.18.1.3] [RN:R02550 R05288 R05442 R05443]	Non-Polyphenol;Aromatic_Hydrocarbon;o-Xylene	o-xylene conversion to o-Toluate (oxic)	step 1 subunit B	o-Xylene => 2-Methylbenzyl alcohol	oxic	EC:1.18.1.3		0
+K00055,EC:1.1.1.90,AA3_2	aryl-alcohol dehydrogenase [EC:1.1.1.90] [RN:R01763 R02611 R04304 R05282 R05347 R05348]	Product of: o-Xylene	o-xylene conversion to o-Toluate (oxic)	step 2	2-Methylbenzyl alcohol => 2-Methylbenzaldehyde	oxic	EC:1.1.1.90		0
+K00141, EC:1.2.1.28	benzaldehyde dehydrogenase (NAD) [EC:1.2.1.28] [RN:R01293 R01419 R05289 R05663 R05664 R07667	Product of: o-Xylene	o-xylene conversion to o-Toluate (oxic)	step 3	2-Methylbenzaldehyde => o-Toluate	oxic	EC:1.2.1.28		0
+K00457	4-hydroxyphenylpyruvate dioxygenase	Polyphenols;Phenolic_acids;Hydroxyphenypropanoic_acids;4-Hydroxyphenypyruvic_Acid	p-hydroxyphenyl conversion to homogentisate (oxic)	step 1	4-hydroxyphenylpyruvate => homogentisate	oxic	EC:1.13.11.27		0
+K15757, EC:1.14.15.26	toluene methyl-monooxygenase [EC:1.14.15.26] [RN:R02550 R05288 R05442 R05443]	Non-Polyphenol;Aromatic_Hydrocarbon;p-Xylene	p-xylene conversion to Toluate (oxic)	step 1 subunit A	p-Xylene => 4-Methylbenzyl alcohol	oxic	EC:1.14.15.26		0
+K15758,EC:1.18.1.3	toluene methyl-monooxygenase electron transfer component [EC:1.18.1.3] [RN:R02550 R05288 R05442 R05443]	Non-Polyphenol;Aromatic_Hydrocarbon;p-Xylene	p-xylene conversion to Toluate (oxic)	step 1 subunit B	p-Xylene => 4-Methylbenzyl alcohol	oxic	EC:1.18.1.3		0
+K00055,EC:1.1.1.90,AA3_2	aryl-alcohol dehydrogenase [EC:1.1.1.90] [RN:R01763 R02611 R04304 R05282 R05347 R05348]	Product of: p-Xylene	p-xylene conversion to Toluate (oxic)	step 2	4-Methylbenzyl alcohol => p-Tolualdehyde	oxic	EC:1.1.1.90		0
+K00141, EC:1.2.1.28	benzaldehyde dehydrogenase (NAD) [EC:1.2.1.28] [RN:R01293 R01419 R05289 R05663 R05664 R07667	Product of: p-Xylene	p-xylene conversion to Toluate (oxic)	step 3	p-Tolualdehyde => Toluate	oxic	EC:1.2.1.28		0
+AA2	AA2 manganese peroxidase (EC 1.11.1.13); versatile peroxidase (EC 1.11.1.16); lignin peroxidase (EC 1.11.1.14); peroxidase (EC 1.11.1.-)	Polyphenols;Polymer	Peroxidase (Non-Specific)	step 1	non-specific	oxic	EC 1.11.1.13,EC 1.11.1.16,EC 1.11.1.14,EC 1.11.1.-	extracellular	0
+K11943	nidA; PAH dioxygenase large subunit [EC:1.13.11.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Phenanthrene	Phenanthrene conversion to Naphthalene-1,2-diol (oxic)	step 1 subunit A	Phenanthrene => (+)-cis-3,4-Dihydrophenanthrene-3,4-diol	oxic			0
+K11944	nidB; PAH dioxygenase small subunit [EC:1.13.11.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Phenanthrene	Phenanthrene conversion to Naphthalene-1,2-diol (oxic)	step 1 subunit B	Phenanthrene => (+)-cis-3,4-Dihydrophenanthrene-3,4-diol	oxic			0
+K18257	phdE; cis-3,4-dihydrophenanthrene-3,4-diol dehydrogenase [EC:1.3.1.49]	Product of: Phenanthrene	Phenanthrene conversion to Naphthalene-1,2-diol (oxic)	step 2	(+)-cis-3,4-Dihydrophenanthrene-3,4-diol => Phenanthrene-3,4-diol	oxic	EC:1.3.1.49		0
+K11945	phdF; extradiol dioxygenase [EC:1.13.11.-]	Product of: Phenanthrene	Phenanthrene conversion to Naphthalene-1,2-diol (oxic)	step 3	Phenanthrene-3,4-diol => 2-Hydroxy-2H-benzo[h]chromene-2-carboxylate	oxic			0
+K11946	phdG; hydratase-aldolase [EC:4.1.2.-]	Product of: Phenanthrene	Phenanthrene conversion to Naphthalene-1,2-diol (oxic)	step 4	cis-4-(1'-Hydroxynaphth-2'-yl)-2-oxobut-3-enoate => 1-Hydroxy-2-naphthaldehyde + Pyruvate	oxic			0
+K11947	nidD; aldehyde dehydrogenase [EC:1.2.1.-]	Product of: Phenanthrene	Phenanthrene conversion to Naphthalene-1,2-diol (oxic)	step 5	1-Hydroxy-2-naphthaldehyde => 1-Hydroxy-2-naphthoate	oxic			0
+K00480	salicylate hydroxylase [EC:1.14.13.1]	Product of: Phenanthrene	Phenanthrene conversion to Naphthalene-1,2-diol (oxic)	step 6	1-Hydroxy-2-naphthoate => Naphthalene-1,2-diol	oxic	EC:1.14.13.1		0
+K01612,EC:4.1.1.61,K16239	vanillate/4-hydroxybenzoate decarboxylase subunit C [EC:4.1.1.- 4.1.1.61]	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol conversion to 4-Hydroxybenzoate (anoxic)	step 1 subunit C	Phenol => 4-Hydroxybenzoate	anoxic	EC:4.1.1.61		0
+K21759	vanillate/4-hydroxybenzoate decarboxylase subunit D [EC:4.1.1.- 4.1.1.61]	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol conversion to 4-Hydroxybenzoate (anoxic)	step 1 subunit D	Phenol => 4-Hydroxybenzoate	anoxic	EC:4.1.1.61		0
+K03186	flavin prenyltransferase [EC:2.5.1.129]	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol conversion to 4-Hydroxybenzoate (anoxic)	step 1 subunit F	Phenol => 4-Hydroxybenzoate	anoxic	EC:2.5.1.129		0
+K03380	phenol 2-monooxygenase	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol Conversion to Catechol (oxic)	step 1	phenol => catechol	oxic	EC:1.14.13.7		0
+K16249	dmpK; phenol hydroxylase P0 protein [RN:R10042 R10043]	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol Conversion to Catechol (oxic)	subunit 0	Phenol => Catechol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16243	dmpL; Phenol hydroxylase P1 protein [RN:R10042 R10043]	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol Conversion to Catechol (oxic)	subunit 1	Phenol => Catechol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16244	dmpM; phenol hydroxylase P2 protein [RN:R10042 R10043]	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol Conversion to Catechol (oxic)	subunit 2	Phenol => Catechol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16242	dmpN; phenol hydroxylase P3 protein [EC:1.14.13.-] [RN:R10042 R10043]	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol Conversion to Catechol (oxic)	subunit 3	Phenol => Catechol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16245	dmpO; phenol hydroxylase P4 protein [RN:R10042 R10043]	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol Conversion to Catechol (oxic)	subunit 4	Phenol => Catechol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16246	dmpP; phenol hydroxylase P5 protein [RN:R10042 R10043]	Polyphenols;Other_Polyphenols;Other_Polyphenols;Phenol	Phenol Conversion to Catechol (oxic)	subunit 5	Phenol => Catechol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K01912	paaK;phenylacetate-CoA ligase	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetic_Acid	Phenylacetate conversion to benzoyl-coA (anoxic)	step 1	phenylacetate => phenylacetyl-CoA	anoxic	EC:6.2.1.30		0
+K18360	phenylacetyl-CoA:acceptor oxidoreductase accessory protein	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetyl-CoA	Phenylacetate conversion to benzoyl-coA (anoxic)	step 2 subunit A	phenylacetyl-CoA => phenylglyoxylate	anoxic	EC:1.17.5.1		0
+K18361	phenylacetyl-CoA:acceptor oxidoreductase subunit B	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetyl-CoA	Phenylacetate conversion to benzoyl-coA (anoxic)	step 2 subunit B	phenylacetyl-CoA => phenylglyoxylate	anoxic	EC:1.17.5.1		0
+K18362	phenylacetyl-CoA:acceptor oxidoreductase subunit C	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetyl-CoA	Phenylacetate conversion to benzoyl-coA (anoxic)	step 2 subunit C	phenylacetyl-CoA => phenylglyoxylate	anoxic	EC:1.17.5.1		0
+K18363	phenylacetyl-CoA:acceptor oxidoreductase subunit D	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetyl-CoA	Phenylacetate conversion to benzoyl-coA (anoxic)	step 2 subunit D	phenylacetyl-CoA => phenylglyoxylate	anoxic	EC:1.17.5.1		0
+K18355	phenylglyoxylate dehydrogenase alpha subunit	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylglyoxylate	Phenylacetate conversion to benzoyl-coA (anoxic)	step 3 subunit A	phenylglyoxylate => benzoyl-coA	anoxic	EC:1.2.1.58		0
+K18356	phenylglyoxylate dehydrogenase beta subunit	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylglyoxylate	Phenylacetate conversion to benzoyl-coA (anoxic)	step 3 subunit B	phenylglyoxylate => benzoyl-coA	anoxic	EC:1.2.1.58		0
+K18357	phenylglyoxylate dehydrogenase gamma subunit	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylglyoxylate	Phenylacetate conversion to benzoyl-coA (anoxic)	step 3 subunit C	phenylglyoxylate => benzoyl-coA	anoxic	EC:1.2.1.58		0
+K18358	phenylglyoxylate dehydrogenase delta subunit	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylglyoxylate	Phenylacetate conversion to benzoyl-coA (anoxic)	step 3 subunit D	phenylglyoxylate => benzoyl-coA	anoxic	EC:1.2.1.58		0
+K18359	phenylglyoxylate dehydrogenase epsilon subunit	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylglyoxylate	Phenylacetate conversion to benzoyl-coA (anoxic)	step 3 subunit E	phenylglyoxylate => benzoyl-coA	anoxic	EC:1.2.1.58		0
+K01912	paaK;phenylacetate-CoA ligase	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetic_Acid	phenylacteate degradation (oxic)	step 1	phenylacetate => phenylacetyl-CoA	oxic	EC:6.2.1.30		0
+K02609	phenylacetyl-CoA 1,2-epoxidase subunit A	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetyl-CoA	phenylacteate degradation (oxic)	step 2 subunit A	phenylacetyl-CoA => 2-(1,2-epoxy-1,2-dihydrophenyl)acetyl-CoA	oxic	EC:1.14.13.149		0
+K02610	phenylacetyl-CoA 1,2-epoxidase subunit B	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetyl-CoA	phenylacteate degradation (oxic)	step 2 subunit B	phenylacetyl-CoA => 2-(1,2-epoxy-1,2-dihydrophenyl)acetyl-CoA	oxic	EC:1.14.13.149		0
+K02611	phenylacetyl-CoA 1,2-epoxidase subunit C	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetyl-CoA	phenylacteate degradation (oxic)	step 2 subunit C	phenylacetyl-CoA => 2-(1,2-epoxy-1,2-dihydrophenyl)acetyl-CoA	oxic	EC:1.14.13.149		0
+K02612	phenylacetyl-CoA 1,2-epoxidase subunit D	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetyl-CoA	phenylacteate degradation (oxic)	step 2 subunit D	phenylacetyl-CoA => 2-(1,2-epoxy-1,2-dihydrophenyl)acetyl-CoA	oxic	EC:1.14.13.149		0
+K02613	phenylacetyl-CoA 1,2-epoxidase subunit E	Polyphenols;Phenolic_acids;Hydroxyphenylacetic_acids;Phenylacetyl-CoA	phenylacteate degradation (oxic)	step 2 subunit E	phenylacetyl-CoA => 2-(1,2-epoxy-1,2-dihydrophenyl)acetyl-CoA	oxic	EC:1.14.13.149		0
+K15866	1,2-epoxyphenylacetyl-CoA isomerase	Product of: Phenylacetate	phenylacteate degradation (oxic)	step 3	2-(1,2-epoxy-1,2-dihydrophenyl)acetyl-CoA => 2-oxepin-2(3H)-ylideneacetyl-CoA	oxic	EC:5.3.3.18		0
+K02618	oxepin-CoA hydrolase	Product of: Phenylacetate	phenylacteate degradation (oxic)	step 4	2-oxepin-2(3H)-ylideneacetyl-CoA => 3-oxo-5,6-didehydrosuberyl-CoA-semialdehyde	oxic	EC:3.3.2.12		0
+K02618	3-oxo-5,6-dehydrosuberyl-CoA semialdehyde dehydrogenase	Product of: Phenylacetate	phenylacteate degradation (oxic)	step 5	3-oxo-5,6-didehydrosuberyl-CoA-semialdehyde => 3-oxo-5,6-didehydroseryl-CoA	oxic	EC:1.2.1.91		0
+K02615	3-oxo-5,6-dehydrosuberyl-CoA thiolase	Product of: Phenylacetate	phenylacteate degradation (oxic)	step 6	3-oxo-5,6-didehydroseryl-CoA => trans-2,3-dehydroadipyl-CoA	oxic	EC:2.3.1.223		0
+K01692	2,3-dehydroadipyl-CoA hydratase	Product of: Phenylacetate	phenylacteate degradation (oxic)	step 7	trans-2,3-dehydroadipyl-CoA => (3S)-hydroxyadipyl-CoA	oxic	EC:4.2.1.17		0
+K00074	3-hydroxyadipyl-CoA dehydrogenase	Product of: Phenylacetate	phenylacteate degradation (oxic)	step 8	(3S)-hydroxyadipyl-CoA => 3-oxoadipyl-CoA	oxic	EC:1.1.1.157		0
+K05708,EC:1.14.12.19	3-phenylpropionate/trans-cinnamate dioxygenase subunit alpha [EC:1.14.12.19]	Phenolic_acids;Hydroxyphenylpropanoic_acids;3-phenylpropionic_acid	Phenylpropionate degradation (oxic)	step 1 subunit A	3-phenylpropionate => 3-(5,6-dihydroxycylohexa-1,3-dien-1-yl)propionate	oxic	EC:1.14.12.19		0
+K05709	3-phenylpropionate/trans-cinnamate dioxygenase subunit beta [EC:1.14.12.19]	Phenolic_acids;Hydroxyphenylpropanoic_acids;3-phenylpropionic_acid	Phenylpropionate degradation (oxic)	step 1 subunit B	3-phenylpropionate => 3-(5,6-dihydroxycylohexa-1,3-dien-1-yl)propionate	oxic	EC:1.14.12.19		0
+K05710	3-phenylpropionate/trans-cinnamate dioxygenase ferredoxin component	Phenolic_acids;Hydroxyphenylpropanoic_acids;3-phenylpropionic_acid	Phenylpropionate degradation (oxic)	step 1 subunit C	3-phenylpropionate => 3-(5,6-dihydroxycylohexa-1,3-dien-1-yl)propionate	oxic			0
+K00529	3-phenylpropionate/trans-cinnamate dioxygenase ferredoxin reductase component [EC:1.18.1.3]	Phenolic_acids;Hydroxyphenylpropanoic_acids;3-phenylpropionic_acid	Phenylpropionate degradation (oxic)	step 1 subunit D	3-phenylpropionate => 3-(5,6-dihydroxycylohexa-1,3-dien-1-yl)propionate	oxic	EC:1.18.1.3		0
+K05711	2,3-dihydroxy-2,3-dihydrophenylpropionate dehydrogenase [EC:1.3.1.87]	Product of: Phenylpropionate	Phenylpropionate degradation (oxic)	step 2	3-(5,6-dihydroxycylohexa-1,3-dien-1-yl)propionate => 3-(2,3-dihydroxyphenyl)propionate	oxic	EC:1.3.1.87		0
+K05713,EC:1.13.11.16	2,3-dihydroxyphenylpropionate 1,2-dioxygenase [EC:1.13.11.16]	Phenolic_acids;Hydroxyphenylpropanoic_acids;2,3-dihydroxyphenylpropionic_acid	Phenylpropionate degradation (oxic)	step 3	3-(2,3-dihydroxyphenyl)propionate => (2Z,4E)-2-hydroxy-6-oxonona-2,4-diene-1,9-dioate	oxic	EC:1.13.11.16		0
+K05714,EC:3.7.1.14	2-hydroxy-6-oxonona-2,4-dienedioate hydrolase [EC:3.7.1.14]	Product of: Phenylpropionate	Phenylpropionate degradation (oxic)	step 4	(2Z,4E)-2-hydroxy-6-oxonona-2,4-diene-1,9-dioate => (2Z)-2-hydroxypenta-2,4-dienoate	oxic	EC:3.7.1.14		0
+D00023,EC:1.3.1.57	PGR;phloroglucinol reductase	Polyphenols;Other_polyphenols;Other_polyphenols;Phloroglucinol	Phloroglucinol degradation (anoxic)	step 1	phloroglucinol => dihydrophloroglucinol	anoxic	EC:1.3.1.57		0
+K18068,EC:1.14.12.7	phthalate 4,5-dioxygenase [EC:1.14.12.7]	Non-Polyphenol;Aromatic_Hydrocarbon;Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 1 (oxic)	route 1 step 1 Subunit A	Phthalate => Phthalate-4,5-cis-dihydrodiol	oxic	EC:1.14.12.7		0
+K18069	phthalate 4,5-dioxygenase reductase component [EC:1.18.1.-]	Produuct_of:_Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 1 (oxic)	route 1 step 1 Subunit B	Phthalate => Phthalate-4,5-cis-dihydrodiol	oxic			0
+K18067,EC:1.3.1.64	phthalate 4,5-cis-dihydrodiol dehydrogenase [EC:1.3.1.64]	Produuct_of:_Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 1 (oxic)	route 1 step 2	Phthalate-4,5-cis-dihydrodiol. => 4,5-Dihydroxyphthalate	oxic	EC:1.3.1.64		0
+K04102	4,5-dihydroxyphthalate decarboxylase [EC:4.1.1.55]	Produuct_of:_Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 1 (oxic)	route 1 step 3	4,5-Dihydroxyphthalate => 3,4-Dihydroxybenzoate	oxic	EC:4.1.1.55		0
+K18251	phthalate 3,4-dioxygenase subunit alpha [EC:1.14.12.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 2 (oxic)	route 2 step 1 subunit A	Phthalate => Phthalate 3,4-cis-dihydrodiol	oxic			0
+K18252	phthalate 3,4-dioxygenase subunit beta [EC:1.14.12.-]	Produuct_of:_Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 2 (oxic)	route 2 step 1 subunit B	Phthalate => Phthalate 3,4-cis-dihydrodiol	oxic			0
+K18253	phthalate 3,4-dioxygenase ferredoxin component	Produuct_of:_Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 2 (oxic)	route 2 step 1 subunit C	Phthalate => Phthalate 3,4-cis-dihydrodiol	oxic			0
+K18254	phthalate 3,4-dioxygenase ferredoxin reductase component [EC:1.18.1.3]	Produuct_of:_Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 2 (oxic)	route 2 step 2	Phthalate => Phthalate 3,4-cis-dihydrodiol	oxic	EC:1.18.1.3		0
+K18255	phthalate 3,4-cis-dihydrodiol dehydrogenase [EC:1.3.1.-]	Produuct_of:_Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 2 (oxic)	route 2 step 3	Phthalate 3,4-cis-dihydrodiol => 3,4-Dihydroxyphthalate	oxic			0
+K18256	3,4-dihydroxyphthalate decarboxylase [EC:4.1.1.69]	Produuct_of:_Phthalic_Acid	Phthalate conversion to protocatechuic acid Route 2 (oxic)	route 2 step 4	3,4-Dihydroxyphthalate => 3,4-Dihydroxybenzoate	oxic	EC:4.1.1.69		0
+D00032,EC:1.17.9.2	PAH;pinoresinol-a-hydroxylase	Polyphenols;Lignans;Lignans;Pinoresinol	Pinoresinol Conversion (oxic)	step 1	(+)-pinoresinol => (+)-6-hydroxypinoresinol	oxic	EC:1.17.9.2		0
+D00010	BER; benzyl ether reductase	Polyphenols;Lignans;Lignans;Pinoresinol	Pinoresinol Conversion Route 1 (anoxic)	route 1 step 1	pinoresinol => secoisolariciresional	anoxic			0
+D00011	GLM; guaiacol lignan methyltransferase	Polyphenols;Lignans;Lignans;Secoisolariciresinol	Pinoresinol Conversion Route 1 (anoxic)	route 1 step 2	Secoisolariciresinol=> didemethyl-secoisolariciresional	anoxic			0
+D00012	CLD; catechol lignan dehydroxylase	Polyphenols;Lignans;Lignans;Didemethyl-secoisolariciresional	Pinoresinol Conversion Route 1 (anoxic)	route 1 step 3	didemethyl-secoisolariciresional => enterodiol	anoxic			0
+D00013	EDL; END lactonizing enzyme	Polyphenols;Lignans;Lignans;Enterodiol	Pinoresinol Conversion Route 1 (anoxic)	route 1 step 4	enterodiol => enterolactone	anoxic			0
+D00033,EC:1.23.1.2	PinZ; pinoresinol reductase	Polyphenols;Lignans;Lignans;Pinoresinol	Pinoresinol Conversion Route 2 (anoxic)	route 2 step 1	pinoresinol => lariciresional => secoisolariciresional	anoxic	EC:1.23.1.2		0
+AA1	AA1 Laccase / p-diphenol:oxygen oxidoreductase / ferroxidase (EC 1.10.3.2); ; ferroxidase (EC 1.10.3.-); Laccase-like multicopper oxidase (EC 1.10.3.-)	Polyphenols;Polymer	Polyphenol Oxidase (Non-specific)	step 1	non-specific	oxic	EC 1.10.3.2,EC 1.10.3.-	extracellular	0
+K04100	protocatechuate 4,5-dioxygenase, alpha chain	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Protocatechuic_acid	Protocatechuic Acid Degradation- Meta-cleavage (oxic)	step 1 subunit A	protocatechuate => 2-hydroxy-4-carboxymuconic semialdehyde	oxic	EC:1.13.11.8		0
+K04101	protocatechuate 4,5-dioxygenase, beta chain	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Protocatechuic_acid	Protocatechuic Acid Degradation- Meta-cleavage (oxic)	step 1 subunit B	protocatechuate => 2-hydroxy-4-carboxymuconic semialdehyde	oxic	EC:1.13.11.8		0
+K10219 	2-hydroxy-4-carboxymuconic-6-semialdehyde dehydrogenase	Product of: Protocatechuic_Acid	Protocatechuic Acid Degradation- Meta-cleavage (oxic)	step 2	2-hydroxy-4-carboxymuconic semialdehyde hemiacetal => 2-pyrone-4,6-dicarboxylate	oxic	EC:1.1.1.312		0
+K10221	2-pyrone-4,6-dicarboxylate hydrolase	Product of: Protocatechuic_Acid	Protocatechuic Acid Degradation- Meta-cleavage (oxic)	step 3	2-pyrone-4,6-dicarboxylate => (1E)-4-oxobut-1-ene-1,2,4-tricarboxylate	oxic	EC:3.1.1.57		0
+K16514	4-oxalomesaconate tautomerase	Product of: Protocatechuic_Acid	Protocatechuic Acid Degradation- Meta-cleavage (oxic)	step 4	(1E)-4-oxobut-1-ene-1,2,4-tricarboxylate => (1E,3E)-4-hydroxybuta-1,3-diene-1,2,4-tricarboxylate	oxic	EC:5.3.2.8		0
+K10220,K16515 	4-oxalomescaconate hydratase	Product of: Protocatechuic_Acid	Protocatechuic Acid Degradation- Meta-cleavage (oxic)	step 5	(1E,3E)-4-hydroxybuta-1,3-diene-1,2,4-tricarboxylate => 2-hydroxy-4-oxobutane-1,2,4-tricarboxylate	oxic	EC:4.2.1.83		0
+K10218	4-oxalocitramalate aldolase	Product of: Protocatechuic_Acid	Protocatechuic Acid Degradation- Meta-cleavage (oxic)	step 6	2-hydroxy-4-oxobutane-1,2,4-tricarboxylate => pyruvate, oxaloacetate	oxic	EC:4.1.3.17		0
+K00448, EC:1.13.11.3	protocatechuate 3,4-dioxygenase, alpha subunit [EC:1.13.11.3]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Protocatechuic_acid	Protocatechuic Acid Degradation- Ortho-cleavage (oxic)	step 1 subunit A	3,4-dihydroxybenzoate => 3-Carboxy-cis,cis-muconate	oxic	EC:1.13.11.3		0
+K00449	protocatechuate 3,4-dioxygenase, beta subunit [EC:1.13.11.3]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Protocatechuic_acid	Protocatechuic Acid Degradation- Ortho-cleavage (oxic)	step 1 subunit B	3,4-dihydroxybenzoate => 3-Carboxy-cis,cis-muconate	oxic	EC:1.13.11.3		0
+K01857,EC:5.5.1.2	3-carboxy-cis,cis-muconate cycloisomerase [EC:5.5.1.2]	Product of: Protocatechuic_Acid	Protocatechuic Acid Degradation- Ortho-cleavage (oxic)	step 2	3-Carboxy-cis,cis-muconate => 4-Carboxymuconolactone	oxic	EC:5.5.1.2		0
+K01607,EC:4.1.1.44	4-carboxymuconolactone decarboxylase [EC:4.1.1.44]	Product of: Protocatechuic_Acid	Protocatechuic Acid Degradation- Ortho-cleavage (oxic)	step 3	4-Carboxymuconolactone => 3-Oxoadipate enol-lactone	oxic	EC:4.1.1.44		0
+K01055, EC:3.1.1.24	3-oxoadipate enol-lactonase [EC:3.1.1.24]	Product of: Protocatechuic_Acid	Protocatechuic Acid Degradation- Ortho-cleavage (oxic)	step 4	3-Oxoadipate enol-lactone => 3-Oxoadipate	oxic	EC:3.1.1.24		0
+D00020,EC:1.97.1.2	pgthA;pyrogallol-phloroglucinol transhydroxylase subunit A	Polyphenols;Other_polyphenols;Other_polyphenols;Pyrogallol	Pyrogallol conversion to phloroglucinol (anoxic)	step 1 subunit A	pyrogallol + 1,2,3,5-tetrahydroxybenzene => phloroglucinol + 1,2,3,5-tetrahydroxybenzene	anoxic	EC:1.97.1.2		0
+D00021	pgthB;pyrogallol-phloroglucinol transhydroxylase subunit B	Polyphenols;Other_polyphenols;Other_polyphenols;Pyrogallol	Pyrogallol conversion to phloroglucinol (anoxic)	step 1 subunit B	pyrogallol + 1,2,3,5-tetrahydroxybenzene => phloroglucinol + 1,2,3,5-tetrahydroxybenzene	anoxic			0
+D00040,K07155,K06911,EC:1.13.11.24	QueD;quercetin-2,3-dioxygenase	Polyphenols;Flavonoids;Flavonols;Quercetin	Quercetin degradation (oxic)	step 1	quercetin => 2-(3,4-dihydroxybenzoyloxy)-4,6-dihydroxybenzoate	oxic	EC:1.13.11.24		0
+D00041,EC:4.1.1.103, K20941	GARD;>-resorcylic acid decarboxylase,EC:4.1.1.103	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;gamma-resorcylate	Resorcylic Acid Degradation (oxic)	step 1	gamma-resorcylate => resorcinol	oxic	EC:4.1.1.103		0
+K20942,K20944,K20943	resorcinol 4-hydroxylase	Polyphenols;Other_polyphenols;Other_polyphenols;Resorcinol	Resorcylic Acid Degradation (oxic)	step 2	resorcinol => hydroxyquinol	oxic	EC:1.14.14.27,EC:1.14.13.220,EC:1.14.13.219		0
+K04098 	hydroxyquinol 1,2-dioxygenase	Polyphenols;Other_Polyphenols;Other_Polyphenols;Hydroxyquinol	Resorcylic Acid Degradation (oxic)	step 3	hydroxyquinol => maleylacetate	oxic	EC:1.13.11.37		0
+D00007,EC:1.13.11.43	LSD;Iignostilbene-e,y-dioxygenase	Polyphenols;Stilbenes;Stilbenes;Resveratrol	Resveratrol conversion to HydroxyBenzaldehydes (oxic)	step 1	resveratrol => 3,5-dihydroxybenzaldehyde + 4-hydroxybenzaldehyde	oxic	EC:1.13.11.43		0
+K00152	salicylaldehyde dehydrogenase	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Salicylaldehyde	Salicylaldehyde conversion to salicylate (oxic)	step 1	salicylaldehyde => salicylate	oxic	EC:1.2.1.65		0
+K00480	nahG; salicylate hydroxylase	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Salicylic_Acid	Salicylic Acid conversion to Catechol (oxic)	step 1	salicylate => catechol	oxic	EC:1.14.13.1	feeds to catechol ortho-cleavage	0
+K21684	salicylyl-CoA 5-hydroxylase	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Salicylyl-CoA	Salicylic Acid conversion to Gentisic Acid Route 1 (oxic)	route 1 step 1	salicyloyl-CoA => gentisyl-CoA	oxic	EC:1.14.13.209	feeds to gentisate degradation	0
+K18242	salicylate-5-hydroxylase	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Salicylic_Acid	Salicylic Acid conversion to Gentisic Acid Route 2 (oxic)	route 2 step 2	salicylate => gentisate	oxic	EC:1.14.13.172	feeds to gentisate degradation	0
+D00008	SesA; THF-dependent sesamin/sesamin-monocatechol methylenetransferase	Polyphenols;Lignans;Lignans;Sesamin	Sesamin Conversion (anoxic)	step 1	sesamin => sesamin mono- => di-catechol + 5,10-CH2-THF	anoxic		sometimes located next to folate metabolism genes	0
+K18074, EC:1.14.12.15	terephthalate 1,2-dioxygenase oxygenase component alpha subunit [EC:1.14.12.15]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzene_Derivative;Terephthalic_acid	Terephthalate Conversion to Protocatechuate (oxic)	step 1 subunit A	Terephalate => cis-4,5-Dihydroxycyclohexa-1(6),2-diene-1,4-dicarboxylate	oxic	EC:1.14.12.15		0
+K18075	terephthalate 1,2-dioxygenase oxygenase component beta subunit [EC:1.14.12.15]	Product of: Terephthalate	Terephthalate Conversion to Protocatechuate (oxic)	step 1 subunit B	Terephalate => cis-4,5-Dihydroxycyclohexa-1(6),2-diene-1,4-dicarboxylate	oxic	EC:1.14.12.15		0
+K18076,EC:1.3.1.53	1,2-dihydroxy-3,5-cyclohexadiene-1,4-dicarboxylate dehydrogenase [EC:1.3.1.53]	Product of: Terephthalate	Terephthalate Conversion to Protocatechuate (oxic)	step 2	cis-4,5-Dihydroxycyclohexa-1(6),2-diene-1,4-dicarboxylate => 3,4-Dihydroxybenzoate	oxic	EC:1.3.1.53		0
+K05549, EC:1.14.12.10	benzoate/toluate 1,2-dioxygenase subunit alpha [EC:1.14.12.10 1.14.12.-] [RN:R05290 R05291 R05428 R05621 R05622 R05665 R08100 R08101 R08108 R08109 R08110]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluic_acid	Toluate degradation to 4-methylcatechol (oxic)	step 1 subunit A	Toluate => cis-1,2-Dihydroxy-4-methylcyclohexa-3,5-diene-1-carboxylate	oxic	EC:1.14.12.10		0
+K05550,EC:1.14.12.10	benzoate/toluate 1,2-dioxygenase subunit beta [EC:1.14.12.10 1.14.12.-] [RN:R05290 R05291 R05428 R05621 R05622 R05665 R08100 R08101 R08108 R08109 R08110]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluic_acid	Toluate degradation to 4-methylcatechol (oxic)	step 1 subunit B	Toluate => cis-1,2-Dihydroxy-4-methylcyclohexa-3,5-diene-1-carboxylate	oxic	EC:1.14.12.10		0
+K05784	benzoate/toluate 1,2-dioxygenasreductase component [EC:1.18.1.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluic_acid	Toluate degradation to 4-methylcatechol (oxic)	step 1 subunit C	Toluate => cis-1,2-Dihydroxy-4-methylcyclohexa-3,5-diene-1-carboxylate	oxic			0
+K05783, EC:1.3.1.25	dihydroxycyclohexadiene carboxylate dehydrogenase [EC:1.3.1.25 1.3.1.-]	Product of: Toluic_Acid	Toluate degradation to 4-methylcatechol (oxic)	step 2	cis-1,2-Dihydroxy-4-methylcyclohexa-3,5-diene-1-carboxylate => 4-Methylcatechol	oxic	EC:1.3.1.25	feeds to catechol meta-cleavage	0
+K15760,EC:1.14.13.236	toluene monooxygenase system protein A [EC:1.14.13.236 1.14.13.-] [RN:R02550 R03562 R05666]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to Benzoate (oxic)	step 1 subunit A	Toluene => Benzyl alcohol	oxic	EC:1.14.13.236		0
+K15761	toluene monooxygenase system protein B [EC:1.14.13.236 1.14.13.-]. [RN:R02550 R03562 R05666]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to Benzoate (oxic)	step 1 subunit B	Toluene => Benzyl alcohol	oxic			0
+K15762	toluene monooxygenase system ferredoxin subunit [RN:R02550 R03562 R05666 R09513]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to Benzoate (oxic)	step 1 subunit C	Toluene => Benzyl alcohol	oxic			0
+K15763	toluene monooxygenase system protein D [EC:1.14.13.236 1.14.13.-] [RN:R02550 R03562 R05666]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to Benzoate (oxic)	step 1 subunit D	Toluene => Benzyl alcohol	oxic			0
+K15764	toluene monooxygenase system protein E [EC:1.14.13.236 1.14.13.-] [RN:R02550 R03562 R05666]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to Benzoate (oxic)	step 1 subunit E	Toluene => Benzyl alcohol	oxic			0
+K15765	toluene monooxygenase electron transfer component [EC:1.18.1.3] [RN:R02550 R03562 R05666 R09513]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to Benzoate (oxic)	step 1 subunit F	Toluene => Benzyl alcohol	oxic	EC:1.18.1.3		0
+K00055,EC:1.1.1.90,AA3_2	aryl-alcohol dehydrogenase [EC:1.1.1.90] [RN:R01763 R02611 R04304 R05282 R05347 R05348]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzyl_alcohol	Toluene Conversion to Benzoate (oxic)	step 2	Benzyl alcohol => Benzaldehyde	oxic	EC:1.1.1.90		0
+K00141, EC:1.2.1.28	benzaldehyde dehydrogenase (NAD) [EC:1.2.1.28] [RN:R01293 R01419 R05289 R05663 R05664 R07667	Non-Polyphenol;Aromatic_Hydrocarbon;Benzaldehyde	Toluene Conversion to Benzoate (oxic)	step 3	Benzaldehyde => Benzoate	oxic	EC:1.2.1.28		0
+K07540,EC:4.1.99.11	benzylsuccinate synthase [EC:4.1.99.11]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to Benzoyl-CoA (anoxic)	step 1	Toluene + Fumarate => Benzylsuccinate	anoxic	EC:4.1.99.11		0
+K07543,EC:2.8.3.15	benzylsuccinate CoA-transferase BbsE subunit [EC:2.8.3.15]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzylsuccinate	Toluene Conversion to Benzoyl-CoA (anoxic)	step 2 subunit A	Benzylsuccinate + Succinyl-CoA => Benzylsuccinyl-CoA + Succinate	anoxic	EC:2.8.3.15		0
+K07544	benzylsuccinate CoA-transferase BbsF subunit [EC:2.8.3.15]	Non-Polyphenol;Aromatic_Hydrocarbon;Benzylsuccinate	Toluene Conversion to Benzoyl-CoA (anoxic)	step 2 subunit B	Benzylsuccinate + Succinyl-CoA => Benzylsuccinyl-CoA + Succinate	anoxic	EC:2.8.3.15		0
+K07545	(R)-benzylsuccinyl-CoA dehydrogenase [EC:1.3.8.3]	Product of: Benzylsuccinate	Toluene Conversion to Benzoyl-CoA (anoxic)	step 3	Benzylsuccinyl-CoA => E-Phenylitaconyl-CoA	anoxic	EC:1.3.8.3		0
+K07546	E-phenylitaconyl-CoA hydratase [EC:4.2.1.-]	Product of: Benzylsuccinate	Toluene Conversion to Benzoyl-CoA (anoxic)	step 4	E-Phenylitaconyl-CoA => (Hydroxymethylphenyl)succinyl-CoA	anoxic			0
+K07549	benzoylsuccinyl-CoA thiolase BbsA subunit [EC:2.3.1.-]	Product of: Benzylsuccinate	Toluene Conversion to Benzoyl-CoA (anoxic)	step 5 subunit A	Benzoylsuccinyl-CoA => Benzoyl-CoA + Succinyl-CoA	anoxic			0
+K07550	benzoylsuccinyl-CoA thiolase BbsB subunit [EC:2.3.1.-]	Product of: Benzylsuccinate	Toluene Conversion to Benzoyl-CoA (anoxic)	step 5 subunit B	Benzoylsuccinyl-CoA => Benzoyl-CoA + Succinyl-CoA	anoxic			0
+K16249	dmpK; phenol hydroxylase P0 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to O-Cresol (oxic)	subunit 0	Toluene  => O-Cresol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16243	dmpL; Phenol hydroxylase P1 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to O-Cresol (oxic)	subunit 1	Toluene  => O-Cresol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16244	dmpM; phenol hydroxylase P2 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to O-Cresol (oxic)	subunit 2	Toluene  => O-Cresol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16242	dmpN; phenol hydroxylase P3 protein [EC:1.14.13.-] [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to O-Cresol (oxic)	subunit 3	Toluene  => O-Cresol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16245	dmpO; phenol hydroxylase P4 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to O-Cresol (oxic)	subunit 4	Toluene  => O-Cresol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K16246	dmpP; phenol hydroxylase P5 protein [RN:R10042 R10043]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene	Toluene Conversion to O-Cresol (oxic)	subunit 5	Toluene  => O-Cresol	oxic	EC:1.14.13.243,EC:1.14.13.244		0
+K15769	p-toluenesulfonate methyl-monooxygenase reductase component TsaB [EC:1.5.1.-]	Non-Polyphenol;Aromatic_Hydrocarbon;Toluene-4-Sulfonate	Toluene-4-Sulfonate conversion to Protocatechuic acid (oxic)	step 1 subunit B	Toluene-4-sulfonate => 4-Sulfobenzyl alcohol	oxic			0
+K15768	p-toluenesulfonate methyl-monooxygenase oxygenase component TsaM [EC:1.14.13.-]	Product of: Toluene-4-sulfonate	Toluene-4-Sulfonate conversion to Protocatechuic acid (oxic)	step 1 subunit M	Toluene-4-sulfonate => 4-Sulfobenzyl alcohol	oxic			0
+K19629	4-(hydroxymethyl)benzenesulfonate dehydrogenase [EC:1.1.1.257]	Product of: Toluene-4-sulfonate	Toluene-4-Sulfonate conversion to Protocatechuic acid (oxic)	step 2	4-Sulfobenzyl alcohol => 4-formylbenzenesulfonate	oxic	EC:1.1.1.257		0
+K19630	4-formylbenzenesulfonate dehydrogenase [EC:1.2.1.62]	Product of: Toluene-4-sulfonate	Toluene-4-Sulfonate conversion to Protocatechuic acid (oxic)	step 3	4-formylbenzenesulfonate => 4-sulfobenzoate	oxic	EC:1.2.1.62		0
+EC:1.14.12.8	4-sulfobenzoate 3,4-dioxygenase	Product of: Toluene-4-sulfonate	Toluene-4-Sulfonate conversion to Protocatechuic acid (oxic)	step 4	4-Sulfobenzoate => 3,4-Dihydroxybenzoate + Sulfite	oxic	EC:1.14.12.8		0
+K00487, EC:1.14.14.91	trans-cinnamate 4-monooxygenase [EC:1.14.14.91]	Polyphenols;Phenolic_Acids;Hydrxoycinnamic_Acids;Trans-Cinnamate	Trans-Cinnamate conversion to Coumarate (oxic)	step 1	trans-cinnamate => 4-coumarate	oxic	EC:1.14.14.91		0
+K05708,EC:1.14.12.19	3-phenylpropionate/trans-cinnamate dioxygenase subunit alpha [EC:1.14.12.19]	Polyphenols;Phenolic_Acids;Hydrxoycinnamic_Acids;Trans-Cinnamate	trans-cinnamate degradation (oxic)	step 1 subunit A	trans-cinnamate => CI-dihydro-diol	oxic	EC:1.14.12.19		0
+K05709	3-phenylpropionate/trans-cinnamate dioxygenase subunit beta [EC:1.14.12.19]	Polyphenols;Phenolic_Acids;Hydrxoycinnamic_Acids;Trans-Cinnamate	trans-cinnamate degradation (oxic)	step 1 subunit B	trans-cinnamate => CI-dihydro-diol	oxic	EC:1.14.12.19		0
+K05710	3-phenylpropionate/trans-cinnamate dioxygenase ferredoxin component	Polyphenols;Phenolic_Acids;Hydrxoycinnamic_Acids;Trans-Cinnamate	trans-cinnamate degradation (oxic)	step 1 subunit C	trans-cinnamate => CI-dihydro-diol	oxic			0
+K00529	3-phenylpropionate/trans-cinnamate dioxygenase ferredoxin reductase component [EC:1.18.1.3]	Polyphenols;Phenolic_Acids;Hydrxoycinnamic_Acids;Trans-Cinnamate	trans-cinnamate degradation (oxic)	step 1 subunit D	trans-cinnamate => CI-dihydro-diol	oxic	EC:1.18.1.3		0
+K05711	2,3-dihydroxy-2,3-dihydrophenylpropionate dehydrogenase [EC:1.3.1.87]	Product of: Trans-Cinnamate	trans-cinnamate degradation (oxic)	step 2	CI-dihydro-diol => trans-2,3-dihydroxy-cinnamate	oxic	EC:1.3.1.87		0
+K05713,EC:1.13.11.16	2,3-dihydroxyphenylpropionate 1,2-dioxygenase [EC:1.13.11.16]	Product of: Trans-Cinnamate	trans-cinnamate degradation (oxic)	step 3	trans-2,3-dihydroxy-cinnamate => 2-hydroxy-6-oxonona-trienedioate	oxic	EC:1.13.11.16		0
+K05714,EC:3.7.1.14	2-hydroxy-6-oxonona-2,4-dienedioate hydrolase [EC:3.7.1.14]	Product of: Trans-Cinnamate	trans-cinnamate degradation (oxic)	step 4	trans-2,3-dihydroxy-cinnamate => 2-hydroxy-6-oxonona-trienedioate=>fumarate+ cis-2-hydroxypenta-2,4-dienoate	oxic	EC:3.7.1.14		0
+K05712,EC:1.14.13.127	3-(3-hydroxy-phenyl)propionate hydroxylase [EC:1.14.13.127]	Product of: Trans-Cinnamate	trans-cinnamate degradation (oxic)	step 1 v2	trans-3-hydroxycinnamate => trans-2,3-dihydroxycinnamate	oxic	EC:1.14.13.127		0
+K03862	vanA; vanillate monooxygenase subunit A	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Vanillic_Acid	vanillate conversion to protocatechuate Route 1 (oxic)	step 1 subunit A	vanillate => protocatechuate, formaldehyde	oxic	EC:1.14.13.82		0
+K03863	vanB; vanillate monooxygenase subunit B	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Vanillic_Acid	vanillate conversion to protocatechuate Route 1 (oxic)	step 1 subunit B	vanillate => protocatechuate, formaldehyde	oxic	EC:1.14.13.82		0
+K15066	ligM; vanillate O-demethylase	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Vanillic_Acid	vanillate conversion to protocatechuate Route 2 (oxic)	step 1	vanillate => protocatechuate	oxic	EC:2.1.1.341		0
+K21802,EC:1.2.1.67    	vanillin dehydrogenase	Polyphenols;Other_Polyphenols;Hydroxybenzaldehydes;Vanillin	vanillin conversion to vanillate (oxic)	step 1	vanillin => vanillate	oxic	EC:1.2.1.67		0
+K20153, EC:1.1.3.38,AA4	vanillyl-alcohol oxidase	Polyphenols;Other_Polyphenols;Hydroxybenzyl_alcohols;Vanillyl_alcohol	Vanillyl-Alcohol conversion to Vanillate (oxic)	step 1	vanillyl-alcohol => vanillate	oxic	EC:1.1.3.38		0
+AA4	AA4 vanillyl-alcohol oxidase (EC 1.1.3.38)	Polyphenols;;;;	Vanillyl-Alcohol Oxidase (Non-Specific)	step 1	non-specific	oxic	EC 1.1.3.38		0
+K15064	desA; syringate O-demethylase [EC:2.1.1.-]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;Syringic_acid	Syringic acid coversion to 3-O-methylgallate (oxic)	step 1	Syringic acid => 3-O-Methylgallate	oxic			0
+K15065	desZ; 3-O-methylgallate 3,4-dioxygenase [EC:1.13.11.-]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;3-o-methylgallic_acid	3-O-methylgallate degradation (oxic)	step 1	3-O-Methylgallate => 4-Carboxy-2-hydroxy-6-methoxy-6-oxohexa-2,4-dienoate	oxic		feeds to K10221	0
+K15066	ligM; 3-O-methylgallate O-demethylase [EC:2.1.1.341]	Polyphenols;Phenolic_acids;Hydroxybenzoic_acids;3-o-methylgallic_acid	3-O-methylgallate coversion to gallate (oxic)	step 1	3-O-Methylgallate => gallate 	oxic	EC:2.1.1.341		0
+K23526	gcoA; aromatic O-demethylase, cytochrome P450 subunit [EC:1.14.14.-]	Polyphenols;Other_polyphenols;Methoxyphenols;Guaiacol	Guaiacol conversion to Catechol (oxic)	step 1 subunit A	Guaiacol => catechol	oxic			0
+K23527	gcoB; aromatic O-demethylase, reductase subunit [EC:1.6.2.-]	Polyphenols;Other_polyphenols;Methoxyphenols;Guaiacol	Guaiacol conversion to Catechol (oxic)	step 1 subunit B	Guaiacol => catechol	oxic			0
diff --git a/tests/data/camper_test_genes.faa b/tests/data/camper_test_genes.faa
new file mode 100644
index 00000000..0b06a5c2
--- /dev/null
+++ b/tests/data/camper_test_genes.faa
@@ -0,0 +1,52 @@
+>20100900_E1D_13_c_000000004265_21 rank: C; sth:STH619 long-chain fatty-acid-CoA ligase; K01897 AMP-binding AMP-binding_C (db=kegg)
+MTARTLNEMLAQSVARFGDKAAFIFKGEIMTFAQLADEIEHCAAGLSELGIAKGDTFGIVMRNCPEFVILSFALSRLGAVAVPVNFLEKADRIAFIFNDAEVKGCLTSKDFLRTIREAKESVPTLEHIFLRDPGGDEPALETIYRHPLDEAAGPEVSPNDLVLLIYTAGTTGLPKGVMLTQRNLLSSVESCLLAFDLTNKDRVMCVLPMFHSFAWTTNVILPLRLGATTVVIESLLPLPPALKQIWKHKVTLVCCIPQVYSALVQHIHGPKAWLLRLLNPLDMAISGAAPLPAAVQIKFEKTFGTALLEGYGLTEAAPAVSVNPRYGAHKPGTVGLPLPGIDIKIVDDDERELETPEIGEVCVRGDNIMAGYYKRPEETKEAFTADGWLKTGDLGFLDSDGYLTLVDRKKDLIIVKGFNVYPQEVEAALVDHPAVAEVAAVGIPDASGDESVRVFVVLEPGQSIKPRELIAFGRETLATYKIPRDVEFVDELPKNALGKVLKRELREGATKSA*
+>20100900_E1D_13_c_000000004272_1 rank: C; css:Cst_c13710 rpsB; 30S ribosomal protein S2; K02967 Ribosomal_S2 (db=kegg)
+LKAKPNQKGAPVSVVSMRELLEAGVHFGHQTRRWNPKMRRYIFTERGGIYIIDLQQTLELLEQAHQFVRNIAERHGTVLFVGTKKQAQDAVAEQAKRVGMPYVNNRWLGGLLTNWRTISGRIERLHELRRLKQESQLELLPAKERLAMLAELEKLETNLGGVADMRRQPDAIFIVDLRKEQLAVREAQRLGLPVVALVDTNCDPEEAEYVIPGNDDAIRSCNLIVRAIADGIMAGKSMTTVEEMTGPADGAEEAAVKTVATAEAEIAATAAPETAAVEESTPAVEESTPAVEESAPAVEESAPAVEAPPQEASSEERESAQ*
+>20100900_E1D_13_c_000000004227_5 rank: C; cwo:Cwoe_5912 ribosomal protein S18; K02963 Ribosomal_S18 (db=kegg)
+MAQQDKKRKRMSASSMPVRRRGCNFCKDHIEEIDWKNTGGLRRYMSERGKIRARRITGVCRRHQRQLAVAIKRAREMALLPYVSD*
+>20100900_E1D_13_c_000000004272_2 rank: C; fbl:Fbal_0953 translation elongation factor Ts (EF-Ts); K02357 EF_TS HOIP-UBA UBA (db=kegg)
+MTEITASLVKDLREQTGAGMMDCKRALQETEGDLEAARKLLREKGMAQAGKRAARATNEGVVLQNLAESVATMVAVACESEPVSVNEAFKTFAGDALARVEADGPGAVDSLEDARVELVAKIGENIVIRDAERFEAAAGEVLAGYVHPPANKIGVLVKLEGGDAELGRLLAMHVSFANPRYLTRDEVPAELVAEERDVYIKQPDVLAKPEQVREKIVEGMLKKRFFAEQVLSDQAWIHDSAKTVAQALAESGAKVVAIRRFALSE*
+>20100900_E1D_13_c_000000004272_3 rank: C; cwo:Cwoe_3515 uridylate kinase; K09903 AA_kinase (db=kegg)
+MGERDHGIDLATVDAIAAEILDVQKSALELAIVLGAGNIYRGIAAAAEGMDRATGDYMGMLATLLNSMALQDALERAGGKTRLMSALAASEVAEPYIRRRAIRHLEKGRVVIFAAGTGNPFFTTDTAAALRALEIGAEAILMAKNGVKGVYDGDPNSDPDAHFLPRLTYLEAIERGLKVMDTTALSLCMDNQLPIYVFELAAGNIKRVAAGERVGTIISNEEV*
+>20100900_E1D_13_c_000000004272_4 rank: C; cwo:Cwoe_3514 ribosome recycling factor; K02838 RRF PKcGMP_CC (db=kegg)
+MPVDDLLVNAANRMDKSVETIHSEFNTVRTGRASTGLLDRIQVEYYGQRTPLQQLATISTPEPRLLTVQPFDPSSFKAVEKAIMESDLGLTPSNDGRVIRLPIPQLTEERRKELVKLVRHMAEEGRVAVRNVRRDLNHHLKELSSSSEIGDDDERRAEEKAQRLTDEHIKIIDELLKVKEAEIMEV*
+>20100900_E1D_13_c_000000004272_5 rank: C; rxy:Rxyl_1402 Undecaprenyl pyrophosphate synthetase; K00806 Prenyltransf (db=kegg)
+MLSLRTRLRALRAISFAKEKTLPTSARSLAIIMDGNGRWARRHGLPNASGHRAGTRALRRTVETCIELEVRSLAVYAFSTENWSRPKDEIDALMTILAETIERELPDLAAQGVRTRFIGRRDRIGEDLRGAMERIETETASNKRLDLWIAFDYGGRDELVWAAKRMLEAGVDPAKLDEEVFTSFLYAPDLPDPDLLIRTSGESRISNFLLWQIAYSELAFVDKLWPEFGPADLRATLQAYTHRRRRFGGRE*
+>20100900_E1D_13_c_000000004272_6 rank: C; vin:AKJ08_1750 Phosphatidate cytidylyltransferase; K00981 CTP_transf_1 CarS-like (db=kegg)
+MSPFASRLAISALGLPIVLALVWGGGWWLFVLLAIAALIGIHEYYLLIRSLHPLVLSGYAGVTITLFGAKLGGLPWMVAGLFGTILLAFAQYGIAKTRQPATIAIGSTLLGVTWVGGGLALLQLIRAIPDGHHHLGQLAAFTVLLTVFAADSAAYGMGRLLGRHKLSPVLSPGKTWEGFVAGVAAAILVSFFALYSNRTDFLSIWEALLFGAIIAVAEALGDLFESSLKRDMHVKDTGRLLGGHGGMLDRIDSLLFAAAAAYFALVAFSVA*
+>20100900_E1D_13_c_000000004272_7 rank: C; cwo:Cwoe_3510 1-deoxy-D-xylulose 5-phosphate reductoisomerase; K00099 DXPR_C DXP_redisom_C DXP_reductoisom PrpR_N DapB_N (db=kegg)
+MKRIALLGATGSIGRQALEIIDAGPELELCALAAGTTDVSGLAADRGVEHFQSGGDLVSLLEACEPDLVLNAVVGFAGCRATLWALEQGVTLALANKESLVAAGELALAAKERGGGLLLPVDSEHSAVFQCLEGRTVEEVTSIVLTASGGPFRGRSRAELERVTPEQALAHPTWQMGPKITIDSATLANKGLEVIEAHFLFGIPYERIEVIVHPGSIVHSLVRFRDGAALAHLGYPDMRVPISFALGYPERPATSIQPLDLAAGLTLEFQALDEETFPLVSLAREAGRTGGSAPCAYSAANEVAVDSFLDGRLPFLSIAEVIERALARADTSAALDLGALVEADAAARRVAAEEVARIEPL*
+>20100900_E1D_13_c_000000004272_8 rank: C; hmr:Hipma_1505 membrane-associated zinc metalloprotease; K11749 Peptidase_M50 PDZ_6 PDZ_2 PDZ Tricorn_PDZ Peptidase_M50B GRASP55_65 (db=kegg)
+MSIFIAILGLALLVLVHETGHFVMARVTGMRPRRFYIGFPPAIAKVTHKGIEYGIGAIPLGGYVKIPGMFRPGKRDPQLYFRPAVAEDESLAEPVQALGQSLESEDLDRARSDLALLNERVESAQLSPASARLAGRGFQELDDSLAPDAYWRQPTWKRLVVIGAGPLTNILVAVLIFASLYMLNTYRLGFNVAANPKTGATTTQVEKVLPNSAAARAGLRAGDVVVTINGKRINGSTMIKRIGASAGRPLTLTVRRHGNLTTLRTVKPMNLALSPPGALAESFRLTWRITRDIFVNGLGRLFERQGQKQISSPVGIVKGSSDAYRHGVSDFLFVIALISLSLGVLNLLPLLPLDGGHVAFSLIERVRGRVVSREIYERVSMAGIAFVLFLFVLGLSNDVHHL*
+>20100900_E1D_13_c_000000004272_9 rank: A; cthm:CFE_1551 4-hydroxy-3-methylbut-2-en-1-yl diphosphate synthase; K03526 GcpE MR_MLE_C Laminin_II (db=kegg)
+MASSRQISVGGVKIGGGAPVAVQSMTTTRARDVEETMAQIDALASAGCEIVRCAVPGLPDAEALSEIVRRSKLPVVADIHFNSSLALKAIAAGVAAVRINPGNIGGPDKVAEVVRAAKQAGTPLRIGANSGSLPEHLRLLAHEDQAQALVAAAMEEVELLERLGFHDFKISVKSTSVPDTIRAYRMLAEKVPYPLHLGVTEAGTVFGGTIKSAIGIGTLLAEGIGDTIRVSLTADPVAEMEVAWGILKALGLRERGPVMISCPTCGRDNVGAQALAEKVEERLRNYDQTFEVAVMGCAVNGPGEAGEADFGIAGGRDVGFIYAHGDVLRKVPVDRLVDELFAELDRWIEAGMQRPRRPRIVKPAAVAMAEAAAAND*
+>20100900_E1D_13_c_000000004272_10 rank: C; fal:FRAAL6288 hypothetical protein; putative signal peptide (db=kegg)
+MRAWFSGHVVLLMILFVVLDTVAIFSAATYKLFIHPHYDTVRRSGAVVVVAGGPLRLKKGIELMQGKVAPLLIVSNPRGAWAYKSEARHLCDGHGVKRPFEVICFDPAPESTQGEARFVKRIAAERHLRSIIVVTSYFHVTRARLEMRRCYHGRLAVIGTPIYNRPKEWFWIAMEWPKLIYAETLNRGC*
+>20100900_E1D_13_c_000000004272_11 rank: E
+MQRLSQLHVPTLRNDPADAEAPSHRLLVRGGYVR
+>20100900_E1D_13_c_000000004192_1 rank: E
+ANPPRGLGIEGSTNATAIVAALLRALVERPALLAEGCLLALVAALIPLARRRGRWGSAGLAGAMIAVGLLPFPGVAATPVLVGAWLTAFALYFLPTAAKSADFAPEPAVTAPLAERRRMAV*
+>20100900_E1D_13_c_000000004192_2 rank: C; cwo:Cwoe_0012 FHA domain containing protein (db=kegg)
+MPLLRTIERRIEAIFEGAFGRAFRAHVQPVELARKLAKEMDDHRTASVTRVYVPNEYTVYLSPDDHDQFSSYEEALCKELQEYLSEHAQREHYALPSAPHVVIETDEDLEIGVFGIATKMARTAQDVPIPEPAPTPSFETTAFSPDIPIDAGAASYALVYPGGRFPLQGDVIALGRARECEIHLSDPNISRRHAEIRLDGGSYAVVDLGSTNGTELNGQRIKNARLSDGDVIAIGQTELTFVRE*
+>20100900_E1D_13_c_000000004192_3 rank: C; chl:Chy400_2143 FHA domain containing protein (db=kegg)
+MALASTSVDGVLLALKIAFIVLLYVFIWRVIRAAGREMRAPDDSFETAPLAERHEKRAPRPGSLVVVSSPNLEEDERLELTHDPLTVGRGPLNDVQLLEDDFASGRHALFDPRRDGVWIEDLGSTNGTFVNGVRLTSSRRLAPGDIVRIGETDFRYER*
+>20100900_E1D_13_c_000000004192_4 rank: C; cwo:Cwoe_0014 protein serine/threonine phosphatase; K20074 PP2C PP2C_2 SpoIIE (db=kegg)
+MSVIGSSARTDTGRRRRRNEDALVCEPPLFAVADGMGGAQAGEVASQLAAESVREQGQGGLAAPEQVIELIRAANRRVYSYSSENASARGMGTTMTVAMVAGDGVVIGHVGDSRAYLLRDDKLTQLTQDHSLVAELIRSGRLSPEEAETHPQRSVITRALGTDPEVEVDLFSLAAKDRDLFLLCSDGLTSMVADEEMERLLVDSRDDLDAATRELIEAANQAGGEDNISVVLFELEVTAVPEEESDVAKTLTEIDAVPALRVEPEEPRRSRRPPRAVLLGMTVAFLIALVALGAYTVSNAHFIGVEPGGHVAIYQGLPYDLPGGIHLYRPVQVSSRLLAAQLTEKERRRLFGHDLQSYGNSKHQLTQYEKVVYP*
+>20100900_E1D_13_c_000000004192_5 rank: A; cwo:Cwoe_0015 cell cycle protein (db=kegg)
+MSARTRELLILILVGLITATGFASVYIARQNEISPASLSYAGFFFVLYLIAHVVARFTVPDADSYLLPMAALLTAIGLTEIYRLGPNDALRQGLWVVIGVAAFAGTLIALRHDFRRLESYKYLFGLSALGLLFLPALPKIGHSVNGARLWVRIGSLQFQPGELGKIAMIVFLAAYLHSKQEVLAQGRPKDFGPLLAIWGCAMLVLVATHDLGSALLFFGIFLAILYLATARLLYVGVGLVLFLAGSAGVYETTAHVRDRVTIWLHPWTTQAIPCPGHSILMPRQECASYQLVKSLYSIAAGGFSGTGLGKGTFTLPGGGNLIPDLNTDFIFSALAQELGLVGIAAILLVFMLFTVHGFRIALVAGDGFSKLVCAGLTFGFALQTFIIIGGIVRLIPLTGITLPFISYGGSSVVANFILLAVLMLVSQRANEPA*
+>20100900_E1D_13_c_000000004192_6 rank: C; cwo:Cwoe_0016 Peptidoglycan glycosyltransferase; K05364 Transpeptidase (db=kegg)
+MNARVRFLALSSLVMLVALIVASTYWQAWAAPDLANKNDNAIRQISEFTIDRGRILAADGTVLARNRVVHTNNRTYYYRRYPLGALTAAAVGYATQNRSRTGLEHSASDYLTGADQSLAGALKQIGDRLLGSTIHGSDIRLSLNLAAQRVAMNALGANCGAAVAIEPSTGRVLELASKPSYNPNDVESHYGRISNIRAACKSASPLVDRATQGLYPPGSSFKIVTAAAALDSGKFTPESIFHDPGYCTEYGQPVKNFADLGRPEVFGTITLFQAFEHSVNSVFCNVGKALEIHPLMDYARRFGFGVKPPIDLPSNSLQASGLYLHGRLLGANEDWRGDPGRVAFGQDKLLVTPLQMAMVAATVANGGVLMRPHLVDKVIRRDGTVDKITPQEIGRAIKPETAAELTQMMEAVVSGGTGTAAQIAGVRVAGKTGTAENGLGRPNTTWFVAFAPADAPRVAVAVVLENQSGTGGTTAAPIAREIMQAILASTANSNS*
+>20100900_E1D_13_c_000000004192_7 rank: A; cwo:Cwoe_0017 serine/threonine protein kinase with PASTA sensor(s); K12132 PASTA Pkinase Pkinase_Tyr APH Kinase-like Kdo RIO1 Pkinase_fungal TPPK_C (db=kegg)
+MTPPDPLIGALFDGRYKVLKKLGSGGMATVYLAEDQELGRRVAIKILNAKHASDEQFVERFRREASSAAGLSHPNIVQIYDRGKAEGTYYIAMEVIEGLSLKELIIKHGPSPIPVAVNYGRQILAALRFAHRNGVVHRDIKPHNVLVDEEGRVKVTDFGIARAGASEMTEVGSIIGTAQYLSPEQARGAPVDARSDLYSVGVVLYELLTGEAPYNGDTPVEIAMKHLSAVPEPPSVKRPEVPPELDAVVLRALAKNPDDRFQSVEEMDADLNAISKGMEISETTTDAATTVLAGAGLSAPTMISRAPTRVVPPSRTGAPMPPPTPPDYYDYDRTPGRRPIWPWLLSLALIAAVGIAFFIVYHQLTGSARVAVPSVTDIREQLAIKKINGAGLSPQSITQTSPTVAAGYVIRQDPLESKHVPRGSTVTIYVSSGTGEIRVPSVVGQSLTEAANTLQNKNFKFRSRTGHSSKPTNVVYQQQPVGNALALKGSTVTVWVSQGPAQVTLPDVTGSLYAQAYSQLQSAGFGVRRVDVPDSSVKGTVIDENPPGNTPQDPGTTVTLSVSKGPSTVLVPDVTQETADQASLDLTAAGFTPQVEYQNTTDVAEDGIVLKQTPAGGKQARPGSTIFISVGQYVASTT*
+>20100900_E1D_13_c_000000004192_8 rank: C; dku:Desku_3098 D-alanine--D-alanine ligase; K01921 Dala_Dala_lig_C Dala_Dala_lig_N ATP-grasp CPSase_L_D2 ATP-grasp_4 ATP-grasp_3 GARS_A DUF2778 (db=kegg)
+MGGRSSEHDISLASAGSVIEALQGRYDTVAIEIDREGRWALPAAAPRELKAGGGERPAETLPVPAESSVPATLAEVDVVFPVLHGPFGEDGTVQGLLELAGVPYIGPGVLASALCMDKDVFKAVLRDRGIPVTQSITLRDGDPVEHPFPYPVFIKPARLGSSVGISKVHDESELGPAVALAFRHDEKVLVEEFVDGLEVECSVLGNRDPIASQPGQIVAHAEWYDFSAKYDEGGMELIVPPPLPEETVELVRRLAVEAFVAGECEGMARVDFFVRGDEVLVNELNTIPGFTSTSVYAKLFAASGISYPELLDRLIALALERHARRQRYAY*
+>20100900_E1D_13_c_000000004192_9 rank: A; thc:TCCBUS3UF1_12040 4-aminobutyrate aminotransferase; K07250 Aminotran_3 (db=kegg)
+MQSSRAIQLLTEIPGPRSREILARKQKVVAAPVTVQAPVVIASALGTVVTDVDGNRFLDFAGGIGCLVVGHSHPRVVEAVREQAGLFLHTDFAVVPYEIYATVAERLIAATPFTGPAKAAFFNSGAEAIENAIKFARLATGRPAVIAFEGGFHGRTLLALTMTSKANPYKVGLGPLAPAVHHLPFAQDYRGPSGAEALAELERALLTQVAPSEVAAVVVEPIQGEGGFVPAPEEFMHGLRRICDEHGIVLVVDEVQSGFGRTGAMFAIEHYGIEPDLIVVAKALASGLPLSGVIGKAEIMDAPHEGAIGGTYVGNPVALAAASAVLDVIEAENLIDRAKALGETIGARMSAWQDRFEQIGDVRGRGAMLAIELVRDRESKEPAPELATRVIEEALQRGLLLLKAGIYSNCLRVLAPLVIGDDELAEALDVWEEALAATFAG*
+>20100900_E1D_13_c_000000004192_10 rank: C; rrd:RradSPS_1030 hypothetical protein (db=kegg)
+MAGRGTNPSTHDAVPRAGTTTKASTEQNPNLPKEIRGIHVTMGLASLSGKLAQYISLKDEGLNTIELDVKDESGAVAFRSPDAPLASAVGAAGNFYKPAEVADQVHADHLYLIGRIAVFEDPVLSARRPEMAIQRSDGSPWLSGGLGWTNEYDKRVWNYNVSIAKVAAKAGFDEIQFDYARFPSDGPISSAVWPGKRNEPESVTIDRFLAYATKQLKPFGVRVSVDVFGLAATNNLGIGQSPGKMARIVDAIYPMVYPSHFGPGQYGLPDPQAVPGTTVGYALNDFATQMHGKKADLVAWLQDFSWQGRPFTLSDVQDEVLAVRRSGARGFLLWNAMGTYTPGALQPAGSNTAVG*
+>20100900_E1D_13_c_000000004192_11 rank: C; deu:DBW_3580 NAD-dependent nucleoside diphosphate-sugar epimerase/dehydratase; K00329,K00356 Epimerase NAD_binding_10 NmrA 3Beta_HSD RmlD_sub_bind GDP_Man_Dehyd NAD_binding_4 Polysacc_synt_2 KR Sacchrp_dh_NADP TrkA_N adh_short Glyco_trans_4_4 Glyco_transf_4 Glyco_trans_4_2 (db=kegg)
+MILVTGATGFIGKHLVATFRSLERPTRCLVRSSSRGRQLEAQGRKLARGDMADPASLRAACDGVDAVVHLVAIIRGRANDYERVMTSGTRALIEAASEAGVRRFVLVSALGLDQSTHGLTPYYQSKWNEERALEASSLEHVIFRPSFVFSHDGGVLPTFLRLVRYSPITPVLGPGTQRIQPISVEDVVAHLVKGLDLEPARDRTFDLAGPDRVSWDELYALIARVLGKRRLRVHIPFSLARAQATLLERLPGFPFTRDQLKMLAAGDNVGDVASTGKVFQLPLISLEEQVRDAIGRA*
+>20100900_E1D_13_c_000000004192_12 rank: C; tro:trd_A0743 O-methyltransferase, family 3 (db=kegg)
+MTPGPAARRVLERLEREDAEERRLGKPREERSRQIAATTGRLLFTLAAARQGCKVLEVGGSRGYSTIWLASAVALGVGRVVSLENDPRKVSAWRANVAEADLDAYAELIEGDAFTTLPALGKCFDLCFIDAEKGDYERLFALAREKITLGSLIVADNVLSHSDTLAAYSRARQSDPTLVSVTVPLDRGLEFSTIIG*
+>20100900_E1D_13_c_000000004192_13 rank: C; rrs:RoseRS_0711 SUF system FeS assembly protein, NifU family; K04488 NifU_N (db=kegg)
+MSVDDLYRELILDHYKSPRHRGRLDRADACAEGQNPLCGDELTVTLRFGADGETIEEIAFEGQGCAISQAAASMLSEEVVGHKATEVAAIDKDDSPLVAMMIESGTPLTPIRLKCALLGLGVLKVALHKAVGTPLPEEWTGVEEVEFE*
diff --git a/tests/data/camper_test_genes_empty.faa b/tests/data/camper_test_genes_empty.faa
new file mode 100644
index 00000000..879fd2d0
--- /dev/null
+++ b/tests/data/camper_test_genes_empty.faa
@@ -0,0 +1,2 @@
+>20100900_E1D_13_c_000000004272_1 rank: C; css:Cst_c13710 rpsB; 30S ribosomal protein S2; K02967 Ribosomal_S2 (db=kegg)
+LKAKPNQKGAPVSVVSMRELLEAGVHFGHQTRRWNPKMRRYIFTERGGIYIIDLQQTLELLEQAHQFVRNIAERHGTVLFVGTKKQAQDAVAEQAKRVGMPYVNNRWLGGLLTNWRTISGRIERLHELRRLKQESQLELLPAKERLAMLAELEKLETNLGGVADMRRQPDAIFIVDLRKEQLAVREAQRLGLPVVALVDTNCDPEEAEYVIPGNDDAIRSCNLIVRAIADGIMAGKSMTTVEEMTGPADGAEEAAVKTVATAEAEIAATAAPETAAVEESTPAVEESTPAVEESAPAVEESAPAVEAPPQEASSEERESAQ*
diff --git a/tests/data/example.fam.subfam.ec.txt b/tests/data/example.fam.subfam.ec.txt
new file mode 100644
index 00000000..d0098cf7
--- /dev/null
+++ b/tests/data/example.fam.subfam.ec.txt
@@ -0,0 +1,6 @@
+# Copyright disclosure: This data is parsed from webpages of www.cazy.org. It is not acurate data
+AA10	AAF22274.1	3.2.1.78
+AA10	AAF96709.1	1.14.99.53
+AA10	AAO80225.1	1.14.99.54
+AA11	AAU22121.1	1.14.99.55
+AA12	AAU39477.1	1.14.99.56
diff --git a/tests/data/test_CONFIG b/tests/data/test_CONFIG
index 3ab8cac2..bcab863e 100644
--- a/tests/data/test_CONFIG
+++ b/tests/data/test_CONFIG
@@ -1,1 +1,27 @@
-{"kegg": null, "kofam": null, "kofam_ko_list": null, "uniref": null, "pfam": "tests/data/Pfam-A_subset.full.gz", "pfam_hmm_dat": "tests/data/Pfam-A_subset.hmm.dat.gz", "dbcan": null, "dbcan_fam_activities": "tests/data/CAZyDB.07312019.fam-activities.subset.txt", "viral": null, "peptidase": null, "vogdb": null, "vog_annotations": "tests/data/vog_annotations_latest.subset.tsv.gz", "genome_summary_form": "data/genome_summary_form.tsv", "module_step_form": "data/module_step_form.tsv", "etc_module_database": "data/etc_module_database.tsv", "function_heatmap_form": "data/function_heatmap_form.tsv", "amg_database": "data/amg_database.tsv"}
\ No newline at end of file
+{
+  "search_databases": {
+    "kegg": null,
+    "kofam": null,
+    "kofam_ko_list": null,
+    "uniref": null,
+    "pfam": null,
+    "dbcan": null,
+    "viral": null,
+    "peptidase": null
+  },
+  "custom_dbs": null,
+  "database_descriptions": {
+    "pfam_hmm_dat": null,
+    "dbcan_fam_activities": null,
+    "vog_annotations": null
+  },
+  "dram_sheets": {
+    "genome_summary_form": null,
+    "module_step_form": null,
+    "etc_module_database": null,
+    "function_heatmap_form": null,
+    "amg_database": null
+  },
+  "description_db": "None",
+  "dram_version": "1.4.0"
+}
diff --git a/tests/data/test_CONFIG_1.3- b/tests/data/test_CONFIG_1.3-
new file mode 100644
index 00000000..4975f80f
--- /dev/null
+++ b/tests/data/test_CONFIG_1.3-
@@ -0,0 +1,1 @@
+{"description_db": "None", "kegg": null, "kofam": null, "kofam_ko_list": null, "uniref": null, "pfam": null, "pfam_hmm_dat": null, "dbcan": null, "dbcan_fam_activities": null, "viral": null, "peptidase": null, "vogdb": null, "vog_annotations": null, "genome_summary_form": null, "module_step_form": null, "etc_module_database": null, "function_heatmap_form": null, "amg_database": null}
diff --git a/tests/data/test_camper_blast_search_formater_hits.tsv b/tests/data/test_camper_blast_search_formater_hits.tsv
new file mode 100644
index 00000000..4f4b3853
--- /dev/null
+++ b/tests/data/test_camper_blast_search_formater_hits.tsv
@@ -0,0 +1,7 @@
+20100900_E1D_13_c_000000004207_31	D00013;Edl	0.239	251	177	0	8	241	5	255	4.292E-19	200
+20100900_E1D_13_c_000000004192_54	D00013;Edl	0.287	252	166	0	8	241	5	256	4.717E-29	120
+20100900_E1D_13_c_000000004278_7	D00013;Edl	0.233	261	193	0	16	276	5	256	9.610E-19	119
+20100900_E1D_13_c_000000004229_4	D00013;Edl	0.230	251	182	0	13	250	5	255	2.145E-17	110
+20100900_E1D_13_c_000000004221_30	D00014;CarE	0.380	57	33	0	4	60	5	58	1.186E-07	301
+20100900_E1D_13_c_000000004302_7	D00014;CarE	0.425	50	26	0	1053	1102	8	53	8.100E-06	240
+20100900_E1D_13_c_000000004275_21	D00014;CarE	0.346	63	29	0	54	116	8	53	1.657E-06	120
diff --git a/tests/data/test_camper_blast_search_formater_out.csv b/tests/data/test_camper_blast_search_formater_out.csv
new file mode 100644
index 00000000..e9e47920
--- /dev/null
+++ b/tests/data/test_camper_blast_search_formater_out.csv
@@ -0,0 +1,5 @@
+qId,CAMPER_hits,CAMPER_rank,CAMPER_bitScore,CAMPER_id,CAMPER_definition,CAMPER_search_type
+20100900_E1D_13_c_000000004207_31,D00013;Edl,A,200,D00013,EDL; END lactonizing enzyme,blast
+20100900_E1D_13_c_000000004192_54,D00013;Edl,B,120,D00013,EDL; END lactonizing enzyme,blast
+20100900_E1D_13_c_000000004221_30,D00014;CarE,A,301,D00014,CarE;electron transfer flavoprotein B,blast
+20100900_E1D_13_c_000000004302_7,D00014;CarE,B,240,D00014,CarE;electron transfer flavoprotein B,blast
diff --git a/tests/data/test_camper_blast_search_formater_scores.tsv b/tests/data/test_camper_blast_search_formater_scores.tsv
new file mode 100644
index 00000000..8fd54d62
--- /dev/null
+++ b/tests/data/test_camper_blast_search_formater_scores.tsv
@@ -0,0 +1,3 @@
+blast_name	A_rank	B_rank	score_type	definition	ID_for_distillate
+D00013;Edl	200	120	full	EDL; END lactonizing enzyme	D00013
+D00014;CarE	300	220	full	CarE;electron transfer flavoprotein B	D00014
diff --git a/tests/data/test_camper_hmmscan_formater_hits.csv b/tests/data/test_camper_hmmscan_formater_hits.csv
new file mode 100644
index 00000000..0dc7d140
--- /dev/null
+++ b/tests/data/test_camper_hmmscan_formater_hits.csv
@@ -0,0 +1,21 @@
+,query_id,query_ascession,query_length,target_id,target_ascession,target_length,full_evalue,full_score,full_bias,domain_number,domain_count,domain_cevalue,domain_ievalue,domain_score,domain_bias,target_start,target_end,alignment_start,alignment_end,query_start,query_end,accuracy,description
+9,20100900_E1D_13_c_000000004291_13,-,403,D00002,-,642,5.2e-08,1028.3,0.1,1,1,8.4e-10,1.2e-07,27.1,0.1,381,540,5,182,1,274,0.74,rank: C; rhq:IM25_00705 pyridine nucleotide-disulfide oxidoreductase (db=kegg)
+10,20100900_E1D_13_c_000000004249_6,-,337,D00002,-,642,1.4e-07,1026.8,0.0,1,1,1.7e-08,2.3e-06,22.8,0.0,383,601,8,259,3,269,0.73,rank: C; tpar:AV541_08380 ferredoxin--NADP(+) reductase; K21567 Pyr_redox_2 Pyr_redox_3 Pyr_redox K_oxygenase HI0933_like FMO-like NAD_binding_9 NAD_binding_7 DAO FAD_binding_2 FAD_binding_3 Thi4 NAD_binding_8 FAD_oxidored Lycopene_cycl Spermine_synth Shikimate_DH Amino_oxidase (db=kegg)
+19,20100900_E1D_13_c_000000004302_7,-,1119,D00001,-,661,6.7e-19,800.0,0.7,1,2,1.3e-08,1.6e-06,23.5,0.0,399,439,140,180,106,192,0.9,rank: A; dfo:Dform_00920 hdrA; heterodisulfide reductase subunit A; K03388 Pyr_redox_2 Fer4_20 Pyr_redox NAD_binding_8 Pyr_redox_3 FAD_oxidored FAD_binding_2 DAO Amino_oxidase Fer4_7 HI0933_like Thi4 Fer4_9 GIDA Fer4 AlaDh_PNT_C Fer4_10 FAD_binding_3 Fer4_21 PALP Fer4_17 (db=kegg)
+20,20100900_E1D_13_c_000000004302_7,-,1119,D00001,-,661,6.7e-19,600.0,0.7,2,2,4.5e-13,5.5e-11,38.2,0.1,397,617,377,630,364,645,0.68,rank: A; dfo:Dform_00920 hdrA; heterodisulfide reductase subunit A; K03388 Pyr_redox_2 Fer4_20 Pyr_redox NAD_binding_8 Pyr_redox_3 FAD_oxidored FAD_binding_2 DAO Amino_oxidase Fer4_7 HI0933_like Thi4 Fer4_9 GIDA Fer4 AlaDh_PNT_C Fer4_10 FAD_binding_3 Fer4_21 PALP Fer4_17 (db=kegg)
+21,20100900_E1D_13_c_000000004274_8,-,320,D00001,-,661,1.9e-12,400.0,0.4,1,2,1.7e-05,0.0021,13.2,0.2,398,424,5,31,2,52,0.75,rank: A; bbw:BDW_01320 thioredoxin reductase; K00384 Pyr_redox_2 Pyr_redox_3 Pyr_redox FAD_binding_2 FAD_binding_3 K_oxygenase DAO HI0933_like FAD_oxidored Thi4 GIDA NAD_binding_8 NAD_binding_7 (db=kegg)
+39,20100900_E1D_13_c_000000004229_6,-,185,D00009,-,547,0.0057,233.4,0.0,1,1,7.2e-06,0.0066,11.8,0.0,104,137,62,95,24,101,0.9,rank: C; tro:trd_1767 oxidoreductase; K19784 FMN_red Flavodoxin_2 (db=kegg)
+40,20100900_E1D_13_c_000000004196_4,-,197,D00009,-,547,0.011,200.0,0.0,1,1,1.4e-05,0.013,10.9,0.0,108,176,69,134,60,179,0.81,rank: C; mhi:Mhar_1480 NAD(P)H dehydrogenase (Quinone) (db=kegg)
+53,20100900_E1D_13_c_000000004225_28,-,467,D00004,-,486,2.6e-06,64.4,0.1,1,2,3.2e-07,9.6e-05,800.0,0.1,7,47,2,42,1,54,0.94,rank: A; nsr:NS506_03143 Glutathione-disulfide reductase; K00382 Pyr_redox_2 Pyr_redox_dim Pyr_redox Pyr_redox_3 FAD_binding_2 FAD_oxidored NAD_binding_8 HI0933_like GIDA DAO NAD_binding_7 FAD_binding_3 Lycopene_cycl 3HCDH_N Trp_halogenase (db=kegg)
+54,20100900_E1D_13_c_000000004225_28,-,467,D00004,-,486,2.6e-06,64.4,0.1,2,2,0.012,3.7,1000.0,0.0,2,38,164,200,163,207,0.88,rank: A; nsr:NS506_03143 Glutathione-disulfide reductase; K00382 Pyr_redox_2 Pyr_redox_dim Pyr_redox Pyr_redox_3 FAD_binding_2 FAD_oxidored NAD_binding_8 HI0933_like GIDA DAO NAD_binding_7 FAD_binding_3 Lycopene_cycl 3HCDH_N Trp_halogenase (db=kegg)
+55,20100900_E1D_13_c_000000004233_24,-,4a74,D00004,-,486,0.00017,43.1,4.6,1,3,6.4e-06,0.002,999.9,0.9,8,57,14,63,10,76,0.89,rank: A; cwo:Cwoe_1859 fumarate reductase/succinate dehydrogenase flavoprotein domain protein; K00278 FAD_binding_2 DAO Pyr_redox_2 HI0933_like GIDA Succ_DH_flav_C Thi4 Trp_halogenase FAD_oxidored Lycopene_cycl NAD_binding_9 NAD_binding_8 HEAT (db=kegg)
+56,20100900_E1D_13_c_000000004233_24,-,474,D00004,-,486,0.00017,17.1,4.6,2,3,0.0055,1.7,200.0,0.0,96,204,89,194,84,263,0.81,rank: A; cwo:Cwoe_1859 fumarate reductase/succinate dehydrogenase flavoprotein domain protein; K00278 FAD_binding_2 DAO Pyr_redox_2 HI0933_like GIDA Succ_DH_flav_C Thi4 Trp_halogenase FAD_oxidored Lycopene_cycl NAD_binding_9 NAD_binding_8 HEAT (db=kegg)
+57,20100900_E1D_13_c_000000004233_24,-,474,D00004,-,486,0.00017,17.1,4.6,3,3,0.51,160.0,2.5,0.0,439,456,330,348,321,351,0.7,rank: A; cwo:Cwoe_1859 fumarate reductase/succinate dehydrogenase flavoprotein domain protein; K00278 FAD_binding_2 DAO Pyr_redox_2 HI0933_like GIDA Succ_DH_flav_C Thi4 Trp_halogenase FAD_oxidored Lycopene_cycl NAD_binding_9 NAD_binding_8 HEAT (db=kegg)
+58,20100900_E1D_13_c_000000004220_17,-,280,D00004,-,486,0.00025,16.6,1.3,1,2,0.00061,0.19,7.1,0.1,11,51,2,42,1,79,0.84,"rank: C; nde:NIDE0310 sdhA; Succinate dehydrogenase/fumarate reductase, flavoprotein subunit; K00239 FAD_binding_2 Succ_DH_flav_C Pyr_redox_2 DAO HI0933_like GIDA FAD_oxidored Thi4 (db=kegg)"
+59,20100900_E1D_13_c_000000004220_17,-,280,D00004,-,486,0.00025,16.6,1.3,2,2,0.00025,0.077,8.4,0.1,133,203,118,190,114,214,0.9,"rank: C; nde:NIDE0310 sdhA; Succinate dehydrogenase/fumarate reductase, flavoprotein subunit; K00239 FAD_binding_2 Succ_DH_flav_C Pyr_redox_2 DAO HI0933_like GIDA FAD_oxidored Thi4 (db=kegg)"
+60,20100900_E1D_13_c_000000004237_20,-,475,D00004,-,486,0.00029,16.4,0.3,1,2,6.5e-06,0.002,13.6,0.0,10,48,147,185,143,211,0.9,rank: A; caby:Cabys_1740 glutamate synthase (NADH) small subunit; K00266 Pyr_redox_2 Fer4_20 NAD_binding_8 Pyr_redox NAD_binding_7 DAO FAD_binding_2 HI0933_like Amino_oxidase FAD_binding_3 FAD_oxidored 2-Hacid_dh_C AlaDh_PNT_C Pyr_redox_3 AdoHcyase_NAD FMO-like IlvN GIDA Thi4 YjeF_N 3HCDH_N NAD_Gly3P_dh_N F420_oxidored NAD_binding_9 Lycopene_cycl Trp_halogenase TrkA_N UDPG_MGDP_dh_N ApbA (db=kegg)
+61,20100900_E1D_13_c_000000004237_20,-,475,D00004,-,486,0.00029,16.4,0.3,2,2,0.068,21.0,0.4,0.1,9,40,285,317,280,320,0.83,rank: A; caby:Cabys_1740 glutamate synthase (NADH) small subunit; K00266 Pyr_redox_2 Fer4_20 NAD_binding_8 Pyr_redox NAD_binding_7 DAO FAD_binding_2 HI0933_like Amino_oxidase FAD_binding_3 FAD_oxidored 2-Hacid_dh_C AlaDh_PNT_C Pyr_redox_3 AdoHcyase_NAD FMO-like IlvN GIDA Thi4 YjeF_N 3HCDH_N NAD_Gly3P_dh_N F420_oxidored NAD_binding_9 Lycopene_cycl Trp_halogenase TrkA_N UDPG_MGDP_dh_N ApbA (db=kegg)
+62,20100900_E1D_13_c_000000004274_8,-,320,D00004,-,486,0.0026,13.3,2.8,1,3,0.00028,0.084,8.3,0.0,9,46,8,45,2,80,0.86,rank: A; bbw:BDW_01320 thioredoxin reductase; K00384 Pyr_redox_2 Pyr_redox_3 Pyr_redox FAD_binding_2 FAD_binding_3 K_oxygenase DAO HI0933_like FAD_oxidored Thi4 GIDA NAD_binding_8 NAD_binding_7 (db=kegg)
+63,20100900_E1D_13_c_000000004274_8,-,320,D00004,-,486,0.0026,13.3,2.8,2,3,0.005,1.5,4.1,0.0,4,39,143,178,140,189,0.85,rank: A; bbw:BDW_01320 thioredoxin reductase; K00384 Pyr_redox_2 Pyr_redox_3 Pyr_redox FAD_binding_2 FAD_binding_3 K_oxygenase DAO HI0933_like FAD_oxidored Thi4 GIDA NAD_binding_8 NAD_binding_7 (db=kegg)
+64,20100900_E1D_13_c_000000004274_8,-,320,D00004,-,486,0.0026,13.3,2.8,3,3,0.13,40.0,-0.6,0.1,153,180,193,221,182,245,0.73,rank: A; bbw:BDW_01320 thioredoxin reductase; K00384 Pyr_redox_2 Pyr_redox_3 Pyr_redox FAD_binding_2 FAD_binding_3 K_oxygenase DAO HI0933_like FAD_oxidored Thi4 GIDA NAD_binding_8 NAD_binding_7 (db=kegg)
+65,20100900_E1D_13_c_000000004302_10,-,805,D00004,-,486,0.014,10.9,0.2,1,1,8.3e-05,0.025,10.0,0.2,10,45,142,177,136,185,0.9,rank: A; mls:MSLAZ_1578 CoB--CoM heterodisulfide reductase subunit A; K03388 FlpD Pyr_redox_2 Fer4_7 Fer4 Fer4_2 Fer4_10 Fer4_21 Fer4_6 Fer4_16 Fer4_9 Pyr_redox_3 DAO Pyr_redox Fer4_8 FAD_oxidored GIDA Fer4_17 FAD_binding_2 NAD_binding_8 K_oxygenase HI0933_like Fer4_4 Thi4 FAD_binding_3 AlaDh_PNT_C Amino_oxidase NAD_binding_7 Lycopene_cycl Fer4_15 3HCDH_N Fer4_22 Fer4_13 (db=kegg)
diff --git a/tests/data/test_camper_hmmscan_formater_out.csv b/tests/data/test_camper_hmmscan_formater_out.csv
new file mode 100644
index 00000000..0c620ee6
--- /dev/null
+++ b/tests/data/test_camper_hmmscan_formater_out.csv
@@ -0,0 +1,5 @@
+,CAMPER_id,CAMPER_rank,CAMPER_bitScore,CAMPER_hits,CAMPER_search_type
+20100900_E1D_13_c_000000004302_7,D00001,A,800.0,FCR; Flavanone/flavanonol-cleaving reductase,hmm
+20100900_E1D_13_c_000000004225_28,D00004,A,1000.0,TDR;tetrahydrodaidzein reductase,hmm
+20100900_E1D_13_c_000000004229_6,D00009,A,233.4,FLR; Flavone/flavonol reductase ,hmm
+20100900_E1D_13_c_000000004196_4,D00009,B,200.0,FLR; Flavone/flavonol reductase ,hmm
diff --git a/tests/data/test_camper_hmmscan_formater_out_notop_hit.csv b/tests/data/test_camper_hmmscan_formater_out_notop_hit.csv
new file mode 100644
index 00000000..69bb4e9f
--- /dev/null
+++ b/tests/data/test_camper_hmmscan_formater_out_notop_hit.csv
@@ -0,0 +1,6 @@
+,CAMPER_id,CAMPER_rank,CAMPER_bitScore,CAMPER_hits,CAMPER_search_type
+20100900_E1D_13_c_000000004302_7,D00001,A,800.0,FCR; Flavanone/flavanonol-cleaving reductase,hmm
+20100900_E1D_13_c_000000004302_7,D00001,B,600.0,FCR; Flavanone/flavanonol-cleaving reductase,hmm
+20100900_E1D_13_c_000000004229_6,D00009,A,233.4,FLR; Flavone/flavonol reductase ,hmm
+20100900_E1D_13_c_000000004196_4,D00009,B,200.0,FLR; Flavone/flavonol reductase ,hmm
+20100900_E1D_13_c_000000004225_28,D00004,A,1000.0,TDR;tetrahydrodaidzein reductase,hmm
diff --git a/tests/data/test_camper_hmmscan_formater_scores.tsv b/tests/data/test_camper_hmmscan_formater_scores.tsv
new file mode 100644
index 00000000..facd5417
--- /dev/null
+++ b/tests/data/test_camper_hmmscan_formater_scores.tsv
@@ -0,0 +1,5 @@
+hmm_name	A_rank	B_rank	score_type	definition
+D00002	800		-	DZR;daidzein reductase
+D00009	225	200	full	FLR; Flavone/flavonol reductase 
+D00001	780	550	full	FCR; Flavanone/flavanonol-cleaving reductase
+D00004	1000		domain	TDR;tetrahydrodaidzein reductase
diff --git a/tests/data/unformatted_cazy.b6 b/tests/data/unformatted_cazy.b6
index d4ec5773..dbea5ddf 100644
--- a/tests/data/unformatted_cazy.b6
+++ b/tests/data/unformatted_cazy.b6
@@ -4,7 +4,7 @@
 bin_1.scaffold_2 -            463 GH1.hmm              -            429    6e-115  377.0  10.2   1   1  7.3e-117  7.3e-115  376.7  10.2     5   427     6   459     3   461 0.92 rank: A; erb:A4V01_06220 glycosyl hydrolase family 1 (db=kegg)
 bin_1.scaffold_2 -            463 GH5.hmm              -            275     6e-08   25.2   7.3   1   1   4.1e-09   4.1e-07   22.5   7.3    34   261    45   443    14   456 0.57 rank: A; erb:A4V01_06220 glycosyl hydrolase family 1 (db=kegg)
 bin_1.scaffold_1 -            478 GT35.hmm             -            674   1.1e-07   23.4   0.0   1   1   2.5e-09   2.5e-07   22.1   0.0   377   527   251   385   245   476 0.76 rank: A; erb:A4V01_04670 starch synthase; K00703 (db=kegg)
-bin_1.scaffold_1 -            478 GT4.hmm              -            160   1.6e-16   53.1   0.0   1   1   3.1e-18   3.1e-16   52.2   0.0    11   142   296   431   288   440 0.87 rank: A; erb:A4V01_04670 starch synthase; K00703 (db=kegg)
+bin_1.scaffold_1 -            478 GT4.hmm              -            160   1.6e-19   53.1   0.0   1   1   3.1e-18   3.1e-16   52.2   0.0    11   142   296   431   288   440 0.87 rank: A; erb:A4V01_04670 starch synthase; K00703 (db=kegg)
 bin_1.scaffold_1 -            478 GT5.hmm              -            472  1.2e-182  600.3   0.6   1   1  1.4e-184  1.4e-182  600.2   0.6     1   471     2   474     2   475 0.98 rank: A; erb:A4V01_04670 starch synthase; K00703 (db=kegg)
 bin_1.other -            155 CBM76.hmm            -            161   0.00079   11.9   0.0   1   1   1.1e-05    0.0011   11.5   0.0    81   153    21    91    11    97 0.82 rank: C; erb:A4V01_09140 hypothetical protein (db=kegg)
 bin_1.scaffold_2 -            463 GH5_19.hmm           -            273   2.6e-05   16.4   0.1   1   1   4.3e-07   4.3e-05   15.6   0.1    24   121    61   155    42   160 0.79 rank: A; erb:A4V01_06220 glycosyl hydrolase family 1 (db=kegg)
diff --git a/tests/test_annotate_bins.py b/tests/test_annotate_bins.py
index 546bf0c0..a0ffb141 100644
--- a/tests/test_annotate_bins.py
+++ b/tests/test_annotate_bins.py
@@ -2,70 +2,38 @@
 
 import os
 from io import StringIO
-from datetime import datetime
+import logging
 from functools import partial
 from filecmp import cmp
 import time
 from shutil import copy
 
 import pandas as pd
+import numpy as np
 from skbio.io import read as read_sequence
 
-from mag_annotator.utils import make_mmseqs_db
-from mag_annotator.database_handler import DatabaseHandler
-from mag_annotator.database_setup import DbcanDescription, create_description_db
+from mag_annotator.utils import make_mmseqs_db, parse_hmmsearch_domtblout, setup_logger
 from mag_annotator.annotate_bins import filter_fasta, run_prodigal, get_best_hits, \
     get_reciprocal_best_hits, process_reciprocal_best_hits, get_kegg_description, get_uniref_description, \
     get_basic_description, get_peptidase_description, get_sig_row, get_gene_data, get_unannotated, assign_grades, \
     generate_annotated_fasta, create_annotated_fasta, generate_renamed_fasta, rename_fasta, run_trna_scan, \
     run_barrnap, do_blast_style_search, count_motifs, strip_endings, process_custom_dbs, get_dups, \
-    parse_hmmsearch_domtblout, annotate_gff, make_gbk_from_gff_and_fasta, make_trnas_interval, make_rrnas_interval,\
-    add_intervals_to_gff, vogdb_hmmscan_formater, generic_hmmscan_formater, dbcan_hmmscan_formater, \
+    annotate_gff, make_gbk_from_gff_and_fasta, make_trnas_interval, make_rrnas_interval,\
+    add_intervals_to_gff, vogdb_hmmscan_formater, dbcan_hmmscan_formater, \
     kofam_hmmscan_formater
 
 
 
-@pytest.fixture()
-def db_handler():
-    return DatabaseHandler(path.join('tests', 'data', 'test_CONFIG'))
-
-
-@pytest.fixture()
-def db_handler_with_dbcan(tmpdir):
-    db_handler = DatabaseHandler(os.path.join('tests', 'data', 'test_CONFIG'))
-    test_db = os.path.join(tmpdir.mkdir('test_db'), 'test_db.sqlite')
-    create_description_db(test_db)
-    db_handler.description_loc = test_db
-    db_handler.start_db_session()
-    dbcan_entries = [{'id': 'GT4', 'description': 'The first description'},
-                     {'id': 'GT5', 'description': 'The second description'},
-                     {'id': 'GH1', 'description': 'A lone description'},
-                     ]
-    db_handler.add_descriptions_to_database(dbcan_entries, 'dbcan_description')
-    #assert len(db_handler.session.query(DbcanDescription).all()) == 3
-    return db_handler
-
-
 @pytest.fixture()
 def fasta_loc():
     return os.path.join('tests', 'data', 'NC_001422.fasta')
 
 
-def test_dbcan_hmmscan_formater(db_handler_with_dbcan):
-    # TODO can we test with db-handler?
-    output_expt = pd.DataFrame({
-        "bin_1.scaffold_1": ["GT4; GT5", 'The first description; The second description'],
-        "bin_1.scaffold_2": ["GH1", 'A lone description']}, 
-                               index=["cazy_id", "cazy_hits"]).T
-    input_b6 = os.path.join('tests', 'data', 'unformatted_cazy.b6')
-    hits = parse_hmmsearch_domtblout(input_b6)
-    output_rcvd = dbcan_hmmscan_formater(hits=hits, db_name='cazy', 
-                                         db_handler=db_handler_with_dbcan)
-    #hits.sort_values('full_evalue').drop_duplicates(subset=["query_id"])
-    # output_rcvd
-    output_rcvd.sort_index(inplace=True)
-    output_expt.sort_index(inplace=True)
-    assert output_rcvd.equals(output_expt), "Error in dbcan_hmmscan_formater"
+@pytest.fixture()
+def logger(tmpdir):
+    logger = logging.getLogger('test_log')
+    setup_logger(logger)
+    return logger
 
 def test_filter_fasta(fasta_loc, tmpdir):
     filtered_seq_5000 = filter_fasta(fasta_loc, min_len=5000)
@@ -79,9 +47,9 @@ def test_filter_fasta(fasta_loc, tmpdir):
 
 
 @pytest.fixture()
-def prodigal_dir(fasta_loc, tmpdir):
+def prodigal_dir(fasta_loc, tmpdir, logger):
     prodigal_output = tmpdir.mkdir('prodigal_output')
-    gff, fna, faa = run_prodigal(fasta_loc, str(prodigal_output))
+    gff, fna, faa = run_prodigal(fasta_loc, str(prodigal_output), logger)
     return gff, fna, faa
 
 
@@ -113,9 +81,9 @@ def mmseqs_db_dir(tmpdir):
 
 
 @pytest.fixture()
-def mmseqs_db(prodigal_faa, mmseqs_db_dir):
+def mmseqs_db(prodigal_faa, mmseqs_db_dir, logger):
     output_file = str(mmseqs_db_dir.join('mmseqs_db.mmsdb'))
-    make_mmseqs_db(prodigal_faa, output_file, True, 1)
+    make_mmseqs_db(prodigal_faa, output_file, logger, True, 1)
     return output_file
 
 
@@ -125,15 +93,15 @@ def phix_proteins():
 
 
 @pytest.fixture()
-def target_mmseqs_db(mmseqs_db_dir, phix_proteins):
+def target_mmseqs_db(mmseqs_db_dir, phix_proteins, logger):
     output_file = str(mmseqs_db_dir.join('target.mmsdb'))
-    make_mmseqs_db(phix_proteins, output_file, True, 1)
+    make_mmseqs_db(phix_proteins, output_file, logger, True, 1)
     return output_file
 
 
 @pytest.fixture()
-def best_hits_loc(mmseqs_db, target_mmseqs_db, mmseqs_db_dir):
-    best_hits_loc = get_best_hits(mmseqs_db, target_mmseqs_db, mmseqs_db_dir, threads=1, verbose=False)
+def best_hits_loc(mmseqs_db, target_mmseqs_db, mmseqs_db_dir, logger):
+    best_hits_loc = get_best_hits(mmseqs_db, target_mmseqs_db, logger, mmseqs_db_dir,threads=1, verbose=False)
     return best_hits_loc
 
 
@@ -142,9 +110,10 @@ def test_get_best_hits(best_hits_loc):
 
 
 @pytest.fixture()
-def reverse_best_hits_loc(best_hits_loc, mmseqs_db, target_mmseqs_db, mmseqs_db_dir):
-    reverse_best_hits_loc = get_reciprocal_best_hits(mmseqs_db, target_mmseqs_db, mmseqs_db_dir, threads=1,
-                                                     verbose=False)
+def reverse_best_hits_loc(best_hits_loc, mmseqs_db, target_mmseqs_db, mmseqs_db_dir, logger):
+    reverse_best_hits_loc = get_reciprocal_best_hits(
+        mmseqs_db, target_mmseqs_db, logger, mmseqs_db_dir, threads=1,
+        verbose=False)
     return reverse_best_hits_loc
 
 
@@ -159,6 +128,20 @@ def processed_hits():
     processed_hits = process_reciprocal_best_hits(forward, reverse)
     return processed_hits
 
+def test_dbcan_hmmscan_formater():
+    # TODO can we test with db-handler?
+    output_expt = pd.DataFrame({"bin_1.scaffold_1": ["GT4; GT5", "GT5.hmm"],
+                           "bin_1.scaffold_2": ["GH1", "GH1.hmm"]}, index=["cazy_ids", "cazy_best_hit"]).T
+    input_b6 = os.path.join('tests', 'data', 'unformatted_cazy.b6')
+    hits = parse_hmmsearch_domtblout(input_b6)
+    output_rcvd = dbcan_hmmscan_formater(hits=hits, db_name='cazy')
+    #hits.sort_values('full_evalue').drop_duplicates(subset=["query_id"])
+    # output_rcvd
+    output_rcvd.sort_index(inplace=True)
+    output_expt.sort_index(inplace=True)
+    assert output_rcvd.equals(output_expt), "Error in dbcan_hmmscan_formater"
+
+
 
 def test_process_reciprocal_best_hits(processed_hits):
     assert processed_hits.shape == (7, 5)
@@ -298,9 +281,9 @@ def test_get_unannotated(phix_proteins):
 def test_assign_grades():
     annotations_data = [[True, 'K00001', False, 'KOER09234OK', ['PF00001']],
                         [False, 'K00002', True, 'KLODKJFSO234KL', ['PF01234']],
-                        [False, 'K00003', False, 'EIORWU234KLKDS', pd.np.NaN],
-                        [False, pd.np.NaN, False, pd.np.NaN, pd.np.NaN],
-                        [False, pd.np.NaN, False, pd.np.NaN, ['PF01235']]]
+                        [False, 'K00003', False, 'EIORWU234KLKDS', np.NaN],
+                        [False, np.NaN, False, np.NaN, np.NaN],
+                        [False, np.NaN, False, np.NaN, ['PF01235']]]
     annotations = pd.DataFrame(annotations_data, index=['gene1', 'gene2', 'gene3', 'gene4', 'gene5'],
                                columns=['kegg_RBH', 'kegg_hit', 'uniref_RBH', 'uniref_hit', 'pfam_hits'])
     test_grades = assign_grades(annotations)
@@ -312,9 +295,9 @@ def test_assign_grades():
     # test no uniref
     annotations_data2 = [[True, 'K00001', ['PF00001']],
                          [False, 'K00002', ['PF01234']],
-                         [False, 'K00003', pd.np.NaN],
-                         [False, pd.np.NaN, pd.np.NaN],
-                         [False, pd.np.NaN, ['PF01235']]]
+                         [False, 'K00003', np.NaN],
+                         [False, np.NaN, np.NaN],
+                         [False, np.NaN, ['PF01235']]]
     annotations2 = pd.DataFrame(annotations_data2, index=['gene1', 'gene2', 'gene3', 'gene4', 'gene5'],
                                 columns=['kegg_RBH', 'kegg_hit', 'pfam_hits'])
     test_grades2 = assign_grades(annotations2)
@@ -402,23 +385,22 @@ def test_rename_fasta(fasta_loc, tmpdir):
     assert os.path.isfile(filt_fasta)
 
 
-def test_run_trna_scan(tmpdir):
+def test_run_trna_scan(tmpdir, logger):
     filt_fasta = tmpdir.mkdir('test_trnascan1')
-    no_trna = run_trna_scan(os.path.join('tests', 'data', 'e_coli_16S.fasta'), str(filt_fasta), 'no_trnas',
-                            threads=1, verbose=False)
+    no_trna = run_trna_scan(os.path.join('tests', 'data', 'e_coli_16S.fasta'), 
+                            str(filt_fasta), 'no_trnas', logger, threads=1, verbose=False)
     assert no_trna is None
 
     filt_fasta = tmpdir.mkdir('test_trnascan2')
     trnas_loc = os.path.join('tests', 'data', 'trnas.fa')
-    trnas = run_trna_scan(trnas_loc, str(filt_fasta), 'phiX', threads=1, verbose=False)
+    trnas = run_trna_scan(trnas_loc, str(filt_fasta), 'phiX', logger, threads=1, verbose=False)
     assert trnas.shape == (6, 9)
 
 
-def test_run_barrnap(fasta_loc):
-    no_rrnas = run_barrnap(fasta_loc, 'phiX', threads=1, verbose=False)
+def test_run_barrnap(fasta_loc, logger):
+    no_rrnas = run_barrnap(fasta_loc, 'phiX', logger, threads=1, verbose=False)
     assert no_rrnas is None
-
-    rrna_table = run_barrnap(os.path.join('tests', 'data', 'e_coli_16S.fasta'), 'coli', threads=1, verbose=False)
+    rrna_table = run_barrnap(os.path.join('tests', 'data', 'e_coli_16S.fasta'), 'coli', logger, threads=1, verbose=False)
     assert rrna_table.shape == (1, 8)
     assert rrna_table.loc[0, 'type'] == '16S rRNA'
     assert rrna_table.loc[0, 'fasta'] == 'coli'
@@ -433,12 +415,13 @@ def get_database_names():
         return []
 
 
-def test_do_blast_style_search(mmseqs_db, target_mmseqs_db, tmpdir):
+def test_do_blast_style_search(mmseqs_db, target_mmseqs_db, tmpdir, logger):
     database_handler = FakeDatabaseHandler()
     working_dir = tmpdir.mkdir('test_blast_search')
     get_fake_description = partial(get_basic_description, db_name='fake')
-    do_blast_style_search(mmseqs_db, target_mmseqs_db, str(working_dir), database_handler, get_fake_description,
-                          datetime.now(), db_name='fake', threads=1)
+    do_blast_style_search(mmseqs_db, target_mmseqs_db, str(working_dir),
+                          database_handler, get_fake_description, logger,
+                          db_name='fake', threads=1)
 
 
 def test_count_motifs(phix_proteins):
@@ -454,14 +437,14 @@ def test_strip_endings():
     assert strip_endings('123456', ['.efg', '.jkl']) == '123456'
 
 
-def test_process_custom_dbs(phix_proteins, tmpdir):
+def test_process_custom_dbs(phix_proteins, tmpdir, logger):
     custom_db_dir = tmpdir.mkdir('custom_dbs')
-    process_custom_dbs([phix_proteins], ['phix'], os.path.join(custom_db_dir, 'custom_dbs0'))
+    process_custom_dbs([phix_proteins], ['phix'], os.path.join(custom_db_dir, 'custom_dbs0'), logger)
     assert os.path.isfile(os.path.join(custom_db_dir, 'custom_dbs0', 'phix.custom.mmsdb'))
-    process_custom_dbs(None, None, os.path.join(custom_db_dir, 'custom_dbs1'))
+    process_custom_dbs(None, None, os.path.join(custom_db_dir, 'custom_dbs1'), logger)
     assert len(os.listdir(os.path.join(custom_db_dir, 'custom_dbs1'))) == 0
     with pytest.raises(ValueError):
-        process_custom_dbs(['thing1', 'thing2'], ['thing1'], os.path.join(custom_db_dir, 'custom_dbs2'))
+        process_custom_dbs(['thing1', 'thing2'], ['thing1'], os.path.join(custom_db_dir, 'custom_dbs2'), logger)
 
 
 def test_get_dubs():
@@ -488,13 +471,13 @@ def annotated_fake_gff_loc():
 
 @pytest.fixture()
 def fake_phix_annotations():
-    return pd.DataFrame([[pd.np.NaN],
+    return pd.DataFrame([[np.NaN],
                          ['GH13'],
-                         [pd.np.NaN],
-                         [pd.np.NaN],
-                         [pd.np.NaN],
-                         [pd.np.NaN],
-                         [pd.np.NaN]],
+                         [np.NaN],
+                         [np.NaN],
+                         [np.NaN],
+                         [np.NaN],
+                         [np.NaN]],
                         index=['NC_001422.1_1', 'NC_001422.1_2', 'NC_001422.1_3', 'NC_001422.1_4',
                                'NC_001422.1_5', 'NC_001422.1_6', 'NC_001422.1_7'],
                         columns=['cazy_id'])
@@ -545,38 +528,6 @@ def test_kofam_hmmscan_formater():
     assert output_rcvd.equals(output_expt), "Error in kofam_hmmscan_formater"
 
 
-def test_generic_hmmscan_formater_custom_cuts():
-    output_expt = pd.DataFrame({
-        "bin_1.scaffold_2": ["K00002", "KO2; description 2"]
-    }, index=["test_id", "test_hits"]).T
-    input_b6 = os.path.join('tests', 'data', 'unformatted_kofam.b6')
-    hits = parse_hmmsearch_domtblout(input_b6)
-    output_rcvd = generic_hmmscan_formater(
-        hits,
-        hmm_info_path=os.path.join('tests', 'data', 'hmm_thresholds.txt'),
-        db_name='test',
-        top_hit=True)
-    output_rcvd.sort_index(inplace=True)
-    output_expt.sort_index(inplace=True)
-    assert output_rcvd.equals(output_expt), "Error in generic_hmmscan_formater, with custom cuts"
-
-
-def test_generic_hmmscan_formater():
-    output_expt = pd.DataFrame({
-        "bin_1.scaffold_1": ["K00001"],
-        "bin_1.scaffold_2": ["K00002"]
-    }, index=["test_id"]).T
-    input_b6 = os.path.join('tests', 'data', 'unformatted_kofam.b6')
-    hits = parse_hmmsearch_domtblout(input_b6)
-    output_rcvd = generic_hmmscan_formater(
-        hits,
-        db_name='test',
-        top_hit=True)
-    output_rcvd.sort_index(inplace=True)
-    output_expt.sort_index(inplace=True)
-    assert output_rcvd.equals(output_expt), "Error in generic_hmmscan_formater"
-
-
 def test_vogdb_hmmscan_formater():
     #TODO Not Done
     output_expt = pd.DataFrame({
@@ -591,6 +542,18 @@ def test_vogdb_hmmscan_formater():
     assert output_rcvd.equals(output_expt), "Error in vogdb_hmmscan_formater"
 
 
+def test_dbcan_hmmscan_formater():
+    # TODO can we test with db-handler?
+    output_expt = pd.DataFrame({"bin_1.scaffold_1": ["GT4; GT5", "GT5.hmm"],
+                           "bin_1.scaffold_2": ["GH1", "GH1.hmm"]}, index=["cazy_ids", "cazy_best_hit"]).T
+    input_b6 = os.path.join('tests', 'data', 'unformatted_cazy.b6')
+    hits = parse_hmmsearch_domtblout(input_b6)
+    output_rcvd = dbcan_hmmscan_formater(hits=hits, db_name='cazy')
+    #hits.sort_values('full_evalue').drop_duplicates(subset=["query_id"])
+    # output_rcvd
+    output_rcvd.sort_index(inplace=True)
+    output_expt.sort_index(inplace=True)
+    assert output_rcvd.equals(output_expt), "Error in dbcan_hmmscan_formater"
 
 
 test_gbk = """LOCUS       NC_001422.1   5386 bp   DNA   linear   ENV   %s
@@ -739,7 +702,7 @@ def test_make_trnas_interval():
     i = 1
 
     test_row1 = {'Begin': 1, 'End': 13, 'Score': 1000, 'Codon': 'AUG', 'Type': 'AUG codon coding tRNA',
-                 'Note': pd.np.NaN}
+                 'Note': np.NaN}
     begin1, end1, metadata1 = make_trnas_interval(test_scaffold, test_row1, i)
     assert begin1 == 1
     assert end1 == 13
@@ -787,11 +750,11 @@ def test_add_intervals_to_gff(annotated_fake_gff_loc, tmpdir):
     annotate_fake_gff_loc_w_rna = os.path.join(add_intervals_test_loc, 'fake.gff')
     copy(annotated_fake_gff_loc, annotate_fake_gff_loc_w_rna)
     fake_rrnas_loc = os.path.join(add_intervals_test_loc, 'rrnas.tsv')
-    fake_rrnas = pd.DataFrame([['fake_NC_001422.1', 990, 1000, 101.0, '+', '16S ribosomal rRNA gene', pd.np.NaN]],
+    fake_rrnas = pd.DataFrame([['fake_NC_001422.1', 990, 1000, 101.0, '+', '16S ribosomal rRNA gene', np.NaN]],
                               columns=['scaffold', 'begin', 'end', 'e-value', 'strand', 'type', 'note'])
     fake_rrnas.to_csv(fake_rrnas_loc, sep='\t')
-    add_intervals_to_gff(fake_rrnas_loc, annotate_fake_gff_loc_w_rna, {'fake_NC_001422.1': 6000}, make_rrnas_interval,
-                         'scaffold')
+    add_intervals_to_gff(fake_rrnas_loc, annotate_fake_gff_loc_w_rna, {'fake_NC_001422.1': 6000}, 
+                         make_rrnas_interval, 'scaffold', logger)
     assert os.path.isfile(annotate_fake_gff_loc_w_rna)
     gff = list(read_sequence(annotate_fake_gff_loc_w_rna, format='gff3'))
     assert type(gff) is list
diff --git a/tests/test_annotate_vgfs.py b/tests/test_annotate_vgfs.py
index db7b3272..8d4d1a38 100644
--- a/tests/test_annotate_vgfs.py
+++ b/tests/test_annotate_vgfs.py
@@ -3,10 +3,16 @@
 import os
 import pandas as pd
 import numpy as np
+import logging
 
 from mag_annotator.annotate_vgfs import calculate_auxiliary_scores, get_virsorter_hits, get_overlap, get_gene_order, \
     is_transposon, get_metabolic_flags, get_amg_ids, get_virsorter_affi_contigs_name
+from mag_annotator.utils import setup_logger
 
+"""
+import os
+os.system("pytest tests/test_annotate_vgfs.py")
+"""
 
 @pytest.fixture()
 def get_data_dir():
@@ -34,6 +40,13 @@ def test_get_overlap():
     assert r_overlap == .5
 
 
+@pytest.fixture()
+def logger(tmpdir):
+    logger = logging.getLogger('test_log')
+    setup_logger(logger)
+    return logger
+
+
 def test_is_transposon():
     assert not is_transposon(np.NaN)
     assert not is_transposon('ABCxyz')
@@ -176,7 +189,7 @@ def test_get_auxilary_score(gene_order1):
                        'dram_gene5': 5}
 
 
-def test_get_metabolic_flags():
+def test_get_metabolic_flags(logger):
     annotations = pd.DataFrame([['scaffold_1', 101, 110, 'Xr', False, 'K00001'],
                                 ['scaffold_1', 234, 423, None, False, 'K00002'],
                                 ['scaffold_2', 52, 105, 'Xs', True, 'K00001'],
@@ -196,7 +209,7 @@ def test_get_metabolic_flags():
                    'scaffold_2': 150,
                    'scaffold_3': 600,
                    'scaffold_4': 1000}
-    flags1 = get_metabolic_flags(annotations, metabolic_genes, amgs, verified_amgs, length_dict, 100)
+    flags1 = get_metabolic_flags(annotations, metabolic_genes, amgs, verified_amgs, length_dict, logger, 100)
     assert flags1 == {'scaffold_1_1': 'VMKE',
                       'scaffold_1_2': 'F',
                       'scaffold_2_1': 'VMKETF',
diff --git a/tests/test_database_handler.py b/tests/test_database_handler.py
index 702eca1d..d4ed2d6b 100644
--- a/tests/test_database_handler.py
+++ b/tests/test_database_handler.py
@@ -1,28 +1,41 @@
 import pytest
 
-from os import path
+from os import path, environ
 from sqlalchemy.orm.exc import NoResultFound
 import json
 
 from mag_annotator.database_setup import KeggDescription, create_description_db
-from mag_annotator.database_handler import DatabaseHandler
+from mag_annotator.database_handler import DatabaseHandler, print_database_locations, import_config, export_config, get_config_loc
+from mag_annotator.utils import setup_logger
+import logging
+import pandas as pd
+import numpy as np
+
+TEST_CONF_PATH = path.join('tests', 'data', 'test_CONFIG')
+TEST_CONF_PATH_1_3 = path.join('tests', 'data', 'test_CONFIG_1.3-')
+
+
+@pytest.fixture()
+def logger(tmpdir):
+    logger = logging.getLogger('test_log')
+    setup_logger(logger)
+    return logger
 
 
 @pytest.fixture()
-def db_handler():
-    return DatabaseHandler(path.join('tests', 'data', 'test_CONFIG'))
+def db_handler(logger):
+    return DatabaseHandler(logger, TEST_CONF_PATH)
 
 
 def test_db_hander_init():  # TODO: this
     pass
 
-def test_add_descriptions_to_database(tmpdir):
-    db_handler = DatabaseHandler(path.join('tests', 'data', 'test_CONFIG'))
+def test_add_descriptions_to_database(tmpdir, logger):
+    db_handler = DatabaseHandler(logger, path.join('tests', 'data', 'test_CONFIG'))
     test_db = path.join(tmpdir.mkdir('test_db'), 'test_db.sqlite')
     create_description_db(test_db)
-    db_handler.description_loc = test_db
+    db_handler.config['description_db'] = test_db
     db_handler.start_db_session()
-
     kegg_entries = [{'id': 'K00001', 'description': 'The first KO'},
                     {'id': 'K00002', 'description': 'The second KO'}]
     db_handler.add_descriptions_to_database(kegg_entries, 'kegg_description')
@@ -34,14 +47,15 @@ def test_add_descriptions_to_database(tmpdir):
 
 
 @pytest.fixture()
-def db_w_entries(tmpdir):
-    db_handler = DatabaseHandler(path.join('tests', 'data', 'test_CONFIG'))
+def db_w_entries(tmpdir, logger):
+    db_handler = DatabaseHandler(logger, path.join('tests', 'data', 'test_CONFIG'))
     test_db = path.join(tmpdir.mkdir('test_db_w_entries'), 'test_db.sqlite')
     create_description_db(test_db)
-    db_handler.description_loc = test_db
+    db_handler.config['description_db'] = test_db
     db_handler.start_db_session()
-    db_handler.add_descriptions_to_database([{'id': 'K00001', 'description': 'The first KO'},
-                                             {'id': 'K00002', 'description': 'The second KO'}],
+    db_handler.add_descriptions_to_database([
+        {'id': 'K00001', 'description': 'The first KO'},
+        {'id': 'K00002', 'description': 'The second KO'}], 
                                             'kegg_description',
                                             clear_table=True)
     return db_handler
@@ -68,54 +82,83 @@ def test_get_database_names(db_w_entries):
     assert len(names) == 7
 
 
-def test_filter_db_locs():
-    db_handler = DatabaseHandler(path.join('tests', 'data', 'test_CONFIG'))
-    db_handler.db_locs = {'kegg': 'a/fake/location/kegg.fasta', 'kofam': 'a/fake/location/kofam.hmm',
-                          'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
-                          'vogdb': 'a/fake/location/vogdb.hmm', 'pfam': 'tests/data/Pfam-A_subset.full.gz',
-                          'dbcan': None, 'peptidase': None, 'uniref': 'a/fake/location/uniref.fasta'}
+def test_filter_db_locs(logger):
+    db_handler = DatabaseHandler(logger, path.join('tests', 'data', 'test_CONFIG'))
+    db_handler.config['search_databases'] = {
+        'kegg': 'a/fake/location/kegg.fasta', 
+        'kofam_hmm': 'a/fake/location/kofam.hmm',
+        'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
+        'vogdb': 'a/fake/location/vogdb.hmm', 
+        'pfam': 'tests/data/Pfam-A_subset.full.gz',
+        'dbcan': None, 'peptidase': None, 'uniref': 'a/fake/location/uniref.fasta'}
     db_handler.filter_db_locs(low_mem_mode=True)
-    assert db_handler.db_locs == {'kofam': 'a/fake/location/kofam.hmm',
-                                  'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
-                                  'pfam': 'tests/data/Pfam-A_subset.full.gz',
-                                  'dbcan': None, 'peptidase': None}
-    db_handler.db_locs = {'kegg': 'a/fake/location/kegg.fasta', 'kofam': 'a/fake/location/kofam.hmm',
-                          'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
-                          'vogdb': 'a/fake/location/vogdb.hmm', 'pfam': 'tests/data/Pfam-A_subset.full.gz',
-                          'dbcan': None, 'peptidase': None}
+    assert db_handler.config.get('search_databases') == {
+        'kofam_hmm': 'a/fake/location/kofam.hmm',
+        'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
+        'pfam': 'tests/data/Pfam-A_subset.full.gz',
+        'dbcan': None, 'peptidase': None}
+    db_handler.config['search_databases'] = {
+        'kegg': 'a/fake/location/kegg.fasta', 
+        'kofam_hmm': 'a/fake/location/kofam.hmm',
+        'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
+        'vogdb': 'a/fake/location/vogdb.hmm', 
+        'pfam': 'tests/data/Pfam-A_subset.full.gz',
+        'dbcan': None, 'peptidase': None}
     db_handler.filter_db_locs(use_vogdb=False)
-    assert db_handler.db_locs == {'kegg': 'a/fake/location/kegg.fasta', 'kofam': 'a/fake/location/kofam.hmm',
-                                  'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
-                                  'pfam': 'tests/data/Pfam-A_subset.full.gz', 'dbcan': None, 'peptidase': None}
-    db_handler.db_locs = {'kegg': 'a/fake/location/kegg.fasta', 'kofam': 'a/fake/location/kofam.hmm',
-                          'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
-                          'vogdb': 'a/fake/location/vogdb.hmm', 'pfam': 'tests/data/Pfam-A_subset.full.gz',
-                          'dbcan': None, 'peptidase': None, 'uniref': 'a/fake/location/uniref.fasta'}
+    assert db_handler.config.get('search_databases') == {
+        'kegg': 'a/fake/location/kegg.fasta', 
+        'kofam_hmm': 'a/fake/location/kofam.hmm',
+        'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
+        'pfam': 'tests/data/Pfam-A_subset.full.gz', 
+        'dbcan': None, 
+        'peptidase': None}
+    db_handler.config['search_databases'] = {
+        'kegg': 'a/fake/location/kegg.fasta', 
+        'kofam_hmm': 'a/fake/location/kofam.hmm',
+        'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
+        'vogdb': 'a/fake/location/vogdb.hmm', 
+        'pfam': 'tests/data/Pfam-A_subset.full.gz',
+        'dbcan': None, 'peptidase': None, 
+        'uniref': 'a/fake/location/uniref.fasta'}
     db_handler.filter_db_locs(use_uniref=False)
-    assert db_handler.db_locs == {'kegg': 'a/fake/location/kegg.fasta', 'kofam': 'a/fake/location/kofam.hmm',
-                                  'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
-                                  'vogdb': 'a/fake/location/vogdb.hmm', 'pfam': 'tests/data/Pfam-A_subset.full.gz',
-                                  'dbcan': None, 'peptidase': None}
+    assert db_handler.config.get('search_databases') == {
+        'kegg': 'a/fake/location/kegg.fasta', 
+        'kofam_hmm': 'a/fake/location/kofam.hmm',
+        'kofam_ko_list': 'a/fake/location/kofam_ko_list.tsv.gz',
+        'vogdb': 'a/fake/location/vogdb.hmm', 
+        'pfam': 'tests/data/Pfam-A_subset.full.gz',
+        'dbcan': None, 'peptidase': None}
     # old version
-    db_handler.db_locs = {'uniref': 'a fake locations', 'kegg': '/a/fake/loc', 'viral': ''}
+    db_handler.config['search_databases'] = {
+        'uniref': 'a fake locations', 
+        'kegg': '/a/fake/loc', 'viral': ''}
     db_handler.filter_db_locs(master_list=('uniref', 'kegg'))
-    assert db_handler.db_locs == {'uniref': 'a fake locations', 'kegg': '/a/fake/loc'}
+    assert db_handler.config.get('search_databases') == {
+        'uniref': 'a fake locations', 
+        'kegg': '/a/fake/loc'}
     # test
-    db_handler.db_locs = {'uniref': 'a fake locations', 'kegg': '/a/fake/loc', 'viral': ''}
+    db_handler.config['search_databases'] = {
+        'uniref': 'a fake locations', 
+        'kegg': '/a/fake/loc', 'viral': ''}
     with pytest.raises(ValueError):
         db_handler.filter_db_locs(low_mem_mode=True)
     # test
-    db_handler.db_locs = {'kofam': '1', 'kofam_ko_list': '2', 'kegg': '/a/fake/loc', 'viral': ''}
+    db_handler.config['search_databases'] = {
+        'kofam_hmm': '1', 'kofam_ko_list': '2', 
+        'kegg': '/a/fake/loc', 'viral': ''}
     db_handler.filter_db_locs(low_mem_mode=True)
-    assert db_handler.db_locs == {'kofam': '1', 'kofam_ko_list': '2', 'viral': ''}
+    assert db_handler.config.get('search_databases') == {
+        'kofam_hmm': '1', 'kofam_ko_list': '2', 'viral': ''}
     # test
-    db_handler.db_locs = {'uniref': 'a fake locations', 'kegg': '/a/fake/loc', 'viral': ''}
+    db_handler.config['search_databases'] = {
+        'uniref': 'a fake locations', 'kegg': '/a/fake/loc', 'viral': ''}
     db_handler.filter_db_locs(use_uniref=True)
-    assert db_handler.db_locs == {'uniref': 'a fake locations', 'kegg': '/a/fake/loc', 'viral': ''}
+    assert db_handler.config.get('search_databases') == {
+        'uniref': 'a fake locations', 'kegg': '/a/fake/loc', 'viral': ''}
     # test
-    db_handler.db_locs = {'uniref': 'a fake locations', 'kegg': '/a/fake/loc', 'viral': ''}
+    db_handler.config['search_databases'] = {'uniref': 'a fake locations', 'kegg': '/a/fake/loc', 'viral': ''}
     db_handler.filter_db_locs(use_uniref=False)
-    assert db_handler.db_locs == {'kegg': '/a/fake/loc', 'viral': ''}
+    assert db_handler.config.get('search_databases') == {'kegg': '/a/fake/loc', 'viral': ''}
 
 
 def test_make_header_dict_from_mmseqs_db():
@@ -144,22 +187,36 @@ def test_process_pfam_descriptions():
 
 def test_process_dbcan_descriptions():
     description_list = DatabaseHandler.process_dbcan_descriptions(
-        path.join('tests', 'data', 'CAZyDB.07312019.fam-activities.subset.txt'))
-    assert description_list == [{'id': 'AA0', 'description': 'AA0'},
-                                {'id': 'AA10', 'description': 'AA10 (formerly CBM33) proteins are copper-dependent '
-                                                              'lytic polysaccharide monooxygenases (LPMOs); some '
-                                                              'proteins have been shown to act on chitin, others on '
-                                                              'cellulose; lytic cellulose monooxygenase '
-                                                              '(C1-hydroxylating) (EC 1.14.99.54); lytic cellulose '
-                                                              'monooxygenase (C4-dehydrogenating)(EC 1.14.99.56); '
-                                                              'lytic chitin monooxygenase (EC 1.14.99.53)'},
-                                {'id': 'AA11', 'description': 'AA11 proteins are copper-dependent lytic polysaccharide '
-                                                              'monooxygenases (LPMOs); cleavage of chitin chains with '
-                                                              'oxidation of C-1 has been demonstrated for a AA11 LPMO '
-                                                              'from Aspergillus oryzae;'},
-                                {'id': 'AA12', 'description': 'AA12 The pyrroloquinoline quinone-dependent oxidoreductase '
-                                                              'activity was demonstrated for the CC1G_09525 protein of '
-                                                              'Coprinopsis cinerea.'}]
+        path.join('tests', 'data', 'CAZyDB.07312019.fam-activities.subset.txt'),
+        path.join('tests', 'data', 'example.fam.subfam.ec.txt'),
+    )
+    expected = pd.DataFrame([
+        {'id': 'AA0', 'description': 'AA0', 'ec': ''},
+        {'id': 'AA10', 
+         'description': 'AA10 (formerly CBM33) proteins are copper-dependent '
+                        'lytic polysaccharide monooxygenases (LPMOs); some '
+                        'proteins have been shown to act on chitin, others on '
+                        'cellulose; lytic cellulose monooxygenase '
+                        '(C1-hydroxylating) (EC 1.14.99.54); lytic cellulose '
+                        'monooxygenase (C4-dehydrogenating)(EC 1.14.99.56); '
+                        'lytic chitin monooxygenase (EC 1.14.99.53)',
+         'ec': '3.2.1.78,1.14.99.53,1.14.99.54'
+         },
+         {'id': 'AA11', 
+          'description': 'AA11 proteins are copper-dependent lytic polysaccharide '
+                         'monooxygenases (LPMOs); cleavage of chitin chains with '
+                         'oxidation of C-1 has been demonstrated for a AA11 LPMO '
+                         'from Aspergillus oryzae;',
+          'ec': '1.14.99.55'
+          },
+         {'id': 'AA12', 
+          'description': 'AA12 The pyrroloquinoline quinone-dependent oxidoreductase '
+                         'activity was demonstrated for the CC1G_09525 protein of '
+                         'Coprinopsis cinerea.',
+          'ec': '1.14.99.56'}
+          ])
+    
+    assert pd.DataFrame(description_list).equals(expected)
 
 
 def test_process_vogdb_descriptions():
@@ -175,38 +232,97 @@ def test_process_vogdb_descriptions():
                                 {'id': 'VOG00005', 'description': 'sp|P17766|POLG_PPVNA Genome polyprotein; XhXrXs'}]
 
 
-def test_export_config(tmpdir, db_handler):
-    test_exported_config = path.join(tmpdir.mkdir('test_export'), 'test_CONFIG')
+def test_export_config(tmpdir):
+    test_exported_config = path.join(tmpdir.mkdir('test_import_config'), 'test_CONFIG')
+    export_config(test_exported_config)
+    assert isinstance(json.loads(open(test_exported_config).read()), dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['search_databases'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['database_descriptions'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['dram_sheets'], dict)
+
+def test_import_config(tmpdir):
+    stash_conf = path.join(tmpdir.mkdir('stash'), 'stash')
+    export_config(stash_conf)
+    import_config(TEST_CONF_PATH)
+    test_exported_config = path.join(tmpdir.mkdir('test_import_config'), 'test_CONFIG')
+    export_config(test_exported_config)
+    import_config(stash_conf)
+    assert isinstance(json.loads(open(test_exported_config).read()), dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['search_databases'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['database_descriptions'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['dram_sheets'], dict)
+
+def test_import_config_old(tmpdir):
+    stash_conf = path.join(tmpdir.mkdir('stash'), 'stash')
+    export_config(stash_conf)
+    import_config(TEST_CONF_PATH_1_3)
+    test_exported_config = path.join(tmpdir.mkdir('test_import_config_old'), 'test_CONFIG')
+    export_config(test_exported_config)
+    import_config(stash_conf)
+    assert isinstance(json.loads(open(test_exported_config).read()), dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['search_databases'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['database_descriptions'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['dram_sheets'], dict)
+
+def test_write_config(tmpdir, db_handler):
+    stash_conf = path.join(tmpdir.mkdir('stash'), 'stash')
+    export_config(stash_conf)
+    test_exported_config = path.join(tmpdir.mkdir('test_write_config'), 'test_CONFIG')
     db_handler.write_config(test_exported_config)
-    assert type(json.loads(open(test_exported_config).read())) is dict
+    import_config(stash_conf)
+    assert isinstance(json.loads(open(test_exported_config).read()), dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['search_databases'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['database_descriptions'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['dram_sheets'], dict)
 
 
-def test_print_database_locations(capsys, db_handler):
-    db_handler.print_database_locations()
+@pytest.fixture()
+def db_handler_1_3(logger):
+    return DatabaseHandler(logger, TEST_CONF_PATH_1_3)
+
+
+def test_construct_from_dram_pre_1_4_0(tmpdir, db_handler_1_3):
+    test_exported_config = path.join(tmpdir.mkdir('test_export'), 'test_CONFIG')
+    db_handler_1_3.write_config(test_exported_config)
+    assert isinstance(json.loads(open(test_exported_config).read()), dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['search_databases'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['database_descriptions'], dict)
+    assert isinstance(json.loads(open(test_exported_config).read())['dram_sheets'], dict)
+
+
+def test_print_database_locations(capsys):
+    print_database_locations()
     out, err = capsys.readouterr()
     assert 'Description db: ' in out
-    assert len(err) == 0
+    assert err.endswith("Logging to console\n")
+
+def test_enviroment_variable(logger):
+    mypath:str = 'my_path_that-is_unique'
+    environ['DRAM_CONFIG_LOCATION'] = mypath
+    assert get_config_loc() == mypath
+    del(environ['DRAM_CONFIG_LOCATION'])
 
 
-def test_set_database_paths():
-    db_handler = DatabaseHandler()
+def test_set_database_paths(logger):
     # first test that adding nothing doesn't change CONFIG
-    pretest_db_dict = db_handler.db_locs
+    db_handler = DatabaseHandler(logger)
+    pretest_db_dict = db_handler.config.get('search_databases')
     db_handler.set_database_paths(write_config=False)
-    assert pretest_db_dict == db_handler.db_locs
+    assert pretest_db_dict == db_handler.config.get('search_databases')
     # test that adding something that doesn't exist throws error
     test_fake_database = path.join('tests', 'data', 'fake_database.mmsdb')
     with pytest.raises(ValueError):
-        db_handler.set_database_paths(kegg_db_loc=test_fake_database, write_config=False)
+        db_handler.set_database_paths(kegg_loc=test_fake_database, write_config=False)
+    
     # test that adding something real is really added
     kegg_loc = path.join('tests', 'data', 'fake_gff.gff')
-    db_handler.set_database_paths(kegg_db_loc=kegg_loc, write_config=False)
-    assert db_handler.db_locs['kegg'] == path.realpath(kegg_loc)
+    db_handler.set_database_paths(kegg_loc=kegg_loc, write_config=False)
+    assert db_handler.config.get('search_databases')['kegg'] == path.realpath(kegg_loc)
 
 
-def test_clear_config():
-    db_handler = DatabaseHandler()
-    db_handler.clear_config()
-    assert db_handler.db_locs == {}
-    assert db_handler.db_description_locs == {}
-    assert db_handler.description_loc is None
+def test_clear_config(logger):
+    db_handler = DatabaseHandler(logger)
+    db_handler.clear_config(write_config=False)
+    assert np.all([i is None for i in db_handler.config['search_databases'].values()])
+    assert np.all([i is None for i in db_handler.config['database_descriptions'].values()])
+    assert db_handler.config['description_db'] is None
diff --git a/tests/test_database_processing.py b/tests/test_database_processing.py
index 85daf85e..aaf2a8d5 100644
--- a/tests/test_database_processing.py
+++ b/tests/test_database_processing.py
@@ -1,7 +1,9 @@
 import pytest
 import os
+import logging
 
-from mag_annotator.database_processing import generate_modified_kegg_fasta, process_kegg_db, process_mmspro
+from mag_annotator.utils import setup_logger
+from mag_annotator.database_processing import generate_modified_kegg_fasta, process_kegg, process_mmspro
 
 @pytest.fixture()
 def phix_proteins():
@@ -12,6 +14,12 @@ def phix_proteins():
 def fake_gene_link_loc():
     return os.path.join('tests', 'data', 'fake_gene_ko.link')
 
+@pytest.fixture()
+def logger(tmpdir):
+    logger = logging.getLogger('test_log')
+    setup_logger(logger)
+    return logger
+
 
 def test_generate_modified_kegg_fasta(phix_proteins, fake_gene_link_loc):
     seqs = generate_modified_kegg_fasta(phix_proteins,
@@ -21,17 +29,26 @@ def test_generate_modified_kegg_fasta(phix_proteins, fake_gene_link_loc):
     assert 'K04464' in seqs_dict['NP_040708.1'].metadata['description']
 
 
-def test_process_kegg_db(tmpdir, phix_proteins, fake_gene_link_loc):
+def test_process_kegg(tmpdir, phix_proteins, fake_gene_link_loc, logger):
     processed_kegg_dir = tmpdir.mkdir('process_kegg_test')
-    kegg_db = process_kegg_db(processed_kegg_dir, phix_proteins, fake_gene_link_loc, download_date='today')
-    assert os.path.isfile(kegg_db)
-    assert os.path.isfile('%s_h' % kegg_db)
+    kegg = process_kegg(phix_proteins, processed_kegg_dir, logger, fake_gene_link_loc, download_date='today')
+    assert os.path.isfile(kegg['kegg'])
+    assert os.path.isfile('%s_h' % kegg['kegg'])
 
 
-def test_process_mmspro(tmpdir):
+def test_process_mmspro(tmpdir, logger):
     processed_mmspro = tmpdir.mkdir('process_mmspro')
-    process_mmspro(os.path.join('tests', 'data', 'Pfam-A_subset.full.gz'), processed_mmspro, 'fake', 1, False)
+    process_mmspro(os.path.join('tests', 'data', 'Pfam-A_subset.full.gz'), processed_mmspro, logger, 'fake', 1, False)
     assert os.path.isfile(os.path.join(processed_mmspro, 'fake.mmspro'))
     assert os.path.isfile(os.path.join(processed_mmspro, 'fake.mmspro_h'))
     # assert os.path.isfile(os.path.join(processed_mmspro, 'fake.mmspro.idx'))
     assert os.path.isfile(os.path.join(processed_mmspro, 'fake.mmspro_h.index'))
+
+
+# def test_down_and_process_camper(tmpdir, logger):
+#     output_dir = tmpdir.mkdir('process_camper')
+#     temporary = os.path.join(output_dir, 'temp')
+#     os.mkdir(temporary)
+#     loc= download_camper_tar_gz(temporary, logger)
+#     process_camper(loc, output_dir, logger)
+
diff --git a/tests/test_database_setup.py b/tests/test_database_setup.py
index d8bcf212..e3411eb6 100644
--- a/tests/test_database_setup.py
+++ b/tests/test_database_setup.py
@@ -13,4 +13,4 @@ def db_loc(tmpdir):
 
 
 def test_create_description_db(db_loc):
-    assert path.isfile(db_loc)
\ No newline at end of file
+    assert path.isfile(db_loc)
diff --git a/tests/test_summarize_genomes.py b/tests/test_summarize_genomes.py
index 41bfb9f7..b8ea5168 100644
--- a/tests/test_summarize_genomes.py
+++ b/tests/test_summarize_genomes.py
@@ -1,6 +1,7 @@
 import pytest
 
 import os
+import logging
 import pandas as pd
 import networkx as nx
 import altair as alt
@@ -10,8 +11,8 @@
     make_module_coverage_heatmap, pairwise, first_open_paren_is_all, split_into_steps, is_ko, make_module_network, \
     get_module_coverage, make_etc_coverage_df, make_etc_coverage_heatmap, make_functional_df, make_functional_heatmap, \
     fill_liquor_dfs, make_liquor_heatmap, make_liquor_df, make_genome_summary, write_summarized_genomes_to_xlsx,\
-    get_phylum_and_most_specific
-from mag_annotator.utils import get_ordered_uniques
+    get_phylum_and_most_specific, get_ids_from_annotations_all, get_ids_from_annotations_by_row
+from mag_annotator.utils import get_ordered_uniques, setup_logger
 
 
 def test_get_ordered_uniques():
@@ -20,6 +21,13 @@ def test_get_ordered_uniques():
     assert get_ordered_uniques([1, 2, 1, 3]) == [1, 2, 3]
 
 
+@pytest.fixture()
+def logger(tmpdir):
+    logger = logging.getLogger('test_log')
+    setup_logger(logger)
+    return logger
+
+
 @pytest.fixture()
 def annotations():
     return pd.DataFrame([['genome', 'K00001'],
@@ -42,8 +50,21 @@ def summarized_genomes():
                         columns=['gene_id', 'gene_description', 'module', 'sheet', 'header', 'subheader', 'genome'])
 
 
-def test_fill_genome_summary_frame(annotations, genome_summary_frame, summarized_genomes):
-    test_frame = fill_genome_summary_frame(annotations, genome_summary_frame, 'fasta')
+def test_get_ids_from_row(logger):
+     in_data = pd.concat([pd.DataFrame({'ko_id': 'K00001,K00003'}, index=['id_set1']),
+                         pd.DataFrame({'kegg_hit': 'Some text and then [EC:0.0.0.0]; also [EC:1.1.1.1]'}, index=['id_set2']),
+                         pd.DataFrame({'peptidase_family': 'ABC1;BCD2'}, index=['id_set3']),
+                         pd.DataFrame({'cazy_hits': 'GH4 some things [GH4]; GT6 other things [GT6]'}, index=['id_set4'])
+                         ])
+     out_data = get_ids_from_annotations_by_row(in_data)
+     assert out_data['id_set1'] == {'K00001', 'K00003'}
+     assert out_data['id_set2'] == {'EC:0.0.0.0', 'EC:1.1.1.1'}
+     assert out_data['id_set3'] == {'ABC1', 'BCD2'}
+     assert out_data['id_set4'] == {'GH4', 'GT6'}
+
+
+def test_fill_genome_summary_frame(annotations, genome_summary_frame, summarized_genomes, logger):
+    test_frame = fill_genome_summary_frame(annotations, genome_summary_frame, 'fasta', logger)
     pd.testing.assert_frame_equal(test_frame, summarized_genomes)
 
 
@@ -77,8 +98,8 @@ def test_summarize_trnas(fake_processed_trnas):
     pd.testing.assert_frame_equal(test_summarized_trnas, summarized_trnas)
 
 
-def test_make_genome_summary(annotations, genome_summary_frame, summarized_genomes):
-    test_genome_summary = make_genome_summary(annotations, genome_summary_frame)
+def test_make_genome_summary(annotations, genome_summary_frame, summarized_genomes, logger):
+    test_genome_summary = make_genome_summary(annotations, genome_summary_frame, logger)
     assert type(test_genome_summary) is pd.DataFrame
     pd.testing.assert_frame_equal(test_genome_summary, summarized_genomes)
 
@@ -206,7 +227,7 @@ def etc_coverage_df():
                                  'complex_module_name'])
 
 
-def test_make_etc_coverage_df(test_annotations_df, etc_module_df, etc_coverage_df):
+def test_make_etc_coverage_df(test_annotations_df, etc_module_df, etc_coverage_df, logger):
     test_etc_coverage_df = make_etc_coverage_df(etc_module_df, test_annotations_df, 'scaffold')
     pd.testing.assert_frame_equal(test_etc_coverage_df, etc_coverage_df)
 
@@ -237,7 +258,7 @@ def functional_df():
 
 
 def test_make_functional_df(test_annotations_df, function_heatmap_form, functional_df):
-    test_functional_df = make_functional_df(test_annotations_df, function_heatmap_form, 'scaffold')
+    test_functional_df = make_functional_df(test_annotations_df, function_heatmap_form, logger, 'scaffold')
     pd.testing.assert_frame_equal(test_functional_df, functional_df)
 
 
@@ -249,7 +270,7 @@ def test_make_functional_heatmap(functional_df):
 # TODO: actually test that the frames are correct, already done above
 def test_fill_liquor_dfs(test_annotations_df, test_module_net, etc_module_df, function_heatmap_form):
     module_nets = {'M12345': test_module_net}
-    liquor_dfs = fill_liquor_dfs(test_annotations_df, module_nets, etc_module_df, function_heatmap_form, 'scaffold')
+    liquor_dfs = fill_liquor_dfs(test_annotations_df, module_nets, etc_module_df, function_heatmap_form, logger, 'scaffold')
     assert len(liquor_dfs) == 3
     assert type(liquor_dfs[0]) is pd.DataFrame
     assert type(liquor_dfs[1]) is pd.DataFrame
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 94da8c74..4c7a191a 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -3,14 +3,22 @@
 import os
 import json
 import pandas as pd
+import logging
 
-from mag_annotator.utils import run_process, make_mmseqs_db, merge_files, multigrep, remove_prefix, remove_suffix, \
-    get_ids_from_row
+from mag_annotator.utils import run_process, make_mmseqs_db, \
+    merge_files, multigrep, remove_prefix, remove_suffix, \
+    setup_logger, parse_hmmsearch_domtblout, generic_hmmscan_formater, download_file
 from mag_annotator.pull_sequences import get_genes_from_identifiers
 
+@pytest.fixture()
+def logger(tmpdir):
+    logger = logging.getLogger('test_log')
+    setup_logger(logger)
+    return logger
+
 
-def test_run_process():
-    run_process(['echo', 'Hello', 'World'], verbose=True)
+def test_run_process(logger):
+    run_process(['echo', 'Hello', 'World'], logger, verbose=True)
     assert True
 
 
@@ -54,6 +62,26 @@ def files_to_merge_w_header(merge_test_dir):
     return files_to_merge
 
 
+def test_download_file(logger, tmpdir):
+    tempfile = tmpdir / 'out'
+    with pytest.raises(URLError):
+        download_file('https://notathingstupid.com', tempfile, logger)
+
+def test_download_file(logger, tmpdir):
+    tempfile = tmpdir / 'out'
+    download_file('https://raw.githubusercontent.com/WrightonLabCSU/DRAM'
+                  '/master/data/function_heatmap_form.tsv',
+                  tempfile, logger)
+    assert os.stat(tempfile).st_size > 0
+    
+def test_download_file(logger, tmpdir):
+    tempfile = tmpdir / 'out'
+    download_file('https://notathingstupid.nothing', tempfile, logger,
+                  alt_urls=['https://raw.githubusercontent.com/'
+                            'WrightonLabCSU/DRAM/master/data/'
+                            'function_heatmap_form.tsv'])
+    assert os.stat(tempfile).st_size > 0
+
 def test_merge_files(files_to_merge_no_header, files_to_merge_w_header, merge_test_dir):
     test_merge = merge_test_dir.join('merged_test.txt')
     merge_files(files_to_merge_no_header, test_merge, False)
@@ -77,9 +105,41 @@ def multigrep_inputs(tmpdir):
     return hits, str(data_file)
 
 
-def test_multigrep(multigrep_inputs):
+def test_generic_hmmscan_formater():
+    output_expt = pd.DataFrame({
+        "bin_1.scaffold_1": ["K00001"],
+        "bin_1.scaffold_2": ["K00002"]
+    }, index=["test_id"]).T
+    input_b6 = os.path.join('tests', 'data', 'unformatted_kofam.b6')
+    hits = parse_hmmsearch_domtblout(input_b6)
+    output_rcvd = generic_hmmscan_formater(
+        hits,
+        db_name='test',
+        top_hit=True)
+    output_rcvd.sort_index(inplace=True)
+    output_expt.sort_index(inplace=True)
+    assert output_rcvd.equals(output_expt), "Error in generic_hmmscan_formater"
+
+
+def test_generic_hmmscan_formater_custom_cuts():
+    output_expt = pd.DataFrame({
+        "bin_1.scaffold_2": ["K00002", "KO2; description 2"]
+    }, index=["test_id", "test_hits"]).T
+    input_b6 = os.path.join('tests', 'data', 'unformatted_kofam.b6')
+    hits = parse_hmmsearch_domtblout(input_b6)
+    output_rcvd = generic_hmmscan_formater(
+        hits,
+        hmm_info_path=os.path.join('tests', 'data', 'hmm_thresholds.txt'),
+        db_name='test',
+        top_hit=True)
+    output_rcvd.sort_index(inplace=True)
+    output_expt.sort_index(inplace=True)
+    assert output_rcvd.equals(output_expt), "Error in generic_hmmscan_formater, with custom cuts"
+
+
+def test_multigrep(multigrep_inputs, logger):
     keys, values = multigrep_inputs
-    dict_ = multigrep(keys, values)
+    dict_ = multigrep(keys, values, logger)
     assert len(dict_) == len(keys)
     assert dict_['gene1'] == 'gene1 something about gene1'
     assert dict_['gene3'] == 'gene3 data including gene3'
@@ -96,17 +156,6 @@ def test_remove_suffix():
     assert remove_suffix('postfix', 'suf') == 'postfix'
 
 
-def test_get_ids_from_row():
-    id_set1 = get_ids_from_row(pd.Series({'ko_id': 'K00001,K00003'}))
-    assert id_set1 == {'K00001', 'K00003'}
-    id_set2 = get_ids_from_row(pd.Series({'kegg_hit': 'Some text and then [EC:0.0.0.0]; also [EC:1.1.1.1]'}))
-    assert id_set2 == {'EC:0.0.0.0', 'EC:1.1.1.1'}
-    id_set3 = get_ids_from_row(pd.Series({'peptidase_family': 'ABC1;BCD2'}))
-    assert id_set3 == {'ABC1', 'BCD2'}
-    id_set4 = get_ids_from_row(pd.Series({'cazy_hits': 'GH4 some things [GH4]; GT6 other things [GT6]'}))
-    assert id_set4 == {'GH4', 'GT6'}
-
-
 @pytest.fixture()
 def annotations():
     return pd.DataFrame([['bin.1', 'scaffold_1', None],