Repository: KohlbacherLab/epytope (language: python)

Issue:
Improve MartsAdapter and support different BioMart references
Currently only certain releases of Ensembl BioMart are supported by [MartsAdapter](https://github.com/KohlbacherLab/epytope/blob/main/epytope/IO/MartsAdapter.py) since the database attribute names changed a multiple times over time.

We should check if the BioMart attributes are stable and if it's feasible to support multiple (and the most recent) versions of Ensembl BioMart (GRCh37 and 38).


Discussion / hints:

Fix patch:
diff --git a/epytope/Core/Generator.py b/epytope/Core/Generator.py
index 64549b7..1aa9703 100644
--- a/epytope/Core/Generator.py
+++ b/epytope/Core/Generator.py
@@ -241,7 +241,6 @@ def _generate_combinations(tId, vs, seq, usedVs, offset, isReverse):
 
     prots = []
     for tId, vs in transToVar.items():
-        #print tId
         query = dbadapter.get_transcript_information(tId, type=id_type, _db=db)
         if query is None:
             logging.warning("Transcript with ID %s not found in DB or sequence unavailable"%tId)
diff --git a/epytope/IO/MartsAdapter.py b/epytope/IO/MartsAdapter.py
index 4f9f796..4f7c207 100755
--- a/epytope/IO/MartsAdapter.py
+++ b/epytope/IO/MartsAdapter.py
@@ -7,18 +7,42 @@
 .. moduleauthor:: walzer, schubert
 """
 
-import csv
-import urllib.request, urllib.error, urllib.parse
+from imghdr import tests
 import warnings
 import logging
 import pymysql.cursors
-from operator import itemgetter
-
+import requests
+from requests.adapters import HTTPAdapter
+from requests.packages.urllib3.util.retry import Retry
+import io
+import pandas as pd
+import re
+import sys
+import xml.etree.ElementTree as ElementTree
+from bs4 import BeautifulSoup
+from enum import Enum
+from html.parser import HTMLParser
 from epytope.IO.ADBAdapter import ADBAdapter, EAdapterFields, EIdentifierTypes
 
 
+class EnsemblMartAttributes(Enum):
+    ENSEMBL_HSAPIENS_DATASET = "hsapiens_gene_ensembl"
+    ENSEMBL_GENE_CONFIG = "gene_ensembl_config"
+    ENSEMBL_GENE_ID = "ensembl_gene_id"
+    ENSEMBL_GENE_ID_VERSION = "ensembl_gene_id_version"
+    ENSEMBL_TRANSCRIPT_ID = "ensembl_transcript_id"
+    ENSEMBL_TRANSCRIPT_ID_VERSION = "ensembl_transcript_id_version"
+    ENSEMBL_PEPTIDE_ID = "ensembl_peptide_id"
+    ENSEMBL_PEPTIDE_ID_VERSION = "ensembl_peptide_id_version"
+    EXTERNAL_GENE_NAME = "external_gene_name"
+    REFSEQ_PEPTIDE = "refseq_peptide"
+    REFSEQ_MRNA_PREDICTED = "refseq_mrna_predicted"
+    REFSEQ_PEPTIDE_PREDICTED = "refseq_peptide_predicted"
+    REFSEQ_MRNA = "refseq_mrna"
+
+
 class MartsAdapter(ADBAdapter):
-    def __init__(self, usr=None, host=None, pwd=None, db=None, biomart=None):
+    def __init__(self, usr=None, host=None, pwd=None, db=None, biomart="https://www.ensembl.org/biomart/martservice", mart_properties=None):
         """
         Used to fetch sequences from given RefSeq id's either from BioMart if no credentials given else from a MySQLdb
 co
@@ -26,47 +50,236 @@ def __init__(self, usr=None, host=None, pwd=None, db=None, biomart=None):
         :param str host: db host e.g. = "pride"
         :param str pwd: pw for user e.g. = 'an0q3ry'
         :param str db: db on host e.g. = "hg18_ucsc_annotation"
+        :param str biomart: Ensembl page url e.g. = "https://www.ensembl.org/"
+        :param dict mart_properties: details for mart query e.g. = ""header":"1""
+
         """
         self.ids_proxy = dict()
         self.gene_proxy = dict()
         self.sequence_proxy = dict()
+        self.biomart_archive_url = "https://www.ensembl.org/info/website/archives/index.html?redirect=no"
+        self.biomart_head = {"virtualSchemaName": "default", "formatter": "TSV",
+                            "header": "1", "uniqueRows": "0", "datasetConfigVersion": "0.6"}
 
         if usr and host and pwd and db:
-            self.connection = pymysql.connect(user=usr, host=host, password=pwd, db=db)
+            self.connection = pymysql.connect(
+                user=usr, host=host, password=pwd, db=db)
         else:
             self.connection = None
 
-        if biomart:
-            self.biomart_url = biomart
-            if not self.biomart_url.endswith("/biomart/martservice?query="):
-                self.biomart_url += "/biomart/martservice?query="
-        else:
-            self.biomart_url = "http://biomart.org/biomart/martservice?query="
-            #new: http://central.biomart.org/biomart/martservice?query="
-            #http://www.ensembl.org/biomart/martview/
-            #http://grch37.ensembl.org/biomart/
-            #http://localhost:9000/biomart/martservice?query=%3C!DOCTYPE%20Query%3E%3CQuery%20client=%22biomartclient%22%20processor=%22TSV%22%20limit=%22-1%22%20header=%221%22%3E%3CDataset%20name=%22hsapiens_gene_ensembl%22%20config=%22gene_ensembl_config%22%3E%3CFilter%20name=%22uniprot_genename%22%20value=%22TP53%22%20filter_list=%22%22/%3E%3CFilter%20name=%22germ_line_variation_source%22%20value=%22dbSNP%22%20filter_list=%22%22/%3E%3CAttribute%20name=%22snp_ensembl_gene_id%22/%3E%3CAttribute%20name=%22snp_chromosome_name%22/%3E%3CAttribute%20name=%22snp_ensembl_transcript_id%22/%3E%3CAttribute%20name=%22snp_start_position%22/%3E%3CAttribute%20name=%22snp_ensembl_peptide_id%22/%3E%3CAttribute%20name=%22snp_end_position%22/%3E%3CAttribute%20name=%22snp_external_gene_name%22/%3E%3CAttribute%20name=%22snp_strand%22/%3E%3CAttribute%20name=%22source_description%22/%3E%3CAttribute%20name=%22germ_line_variation_source%22/%3E%3CAttribute%20name=%22allele%22/%3E%3CAttribute%20name=%22variation_name%22/%3E%3C/Dataset%3E%3C/Query%3E
-            #self.biomart_url = """http://134.2.9.124/biomart/martservice?query="""
-        self.biomart_head = """
-        <?xml version="1.0" encoding="UTF-8"?>
-            <!DOCTYPE Query>
-            <Query client="true" processor="TSV" limit="-1" header="1" uniqueRows = "1" >
-                <Dataset name="%s" config="%s">
-        """.strip()
-        self.biomart_tail = """
-                </Dataset>
-            </Query>
-        """.strip()
-        self.biomart_filter = """<Filter name="%s" value="%s" filter_list=""/>"""
-        self.biomart_attribute = """<Attribute name="%s"/>"""
+        self.biomart_url = biomart
+        if not self.biomart_url.endswith("/biomart/martservice"):
+            self.biomart_url += "/biomart/martservice"
+
+        if mart_properties:
+            self.biomart_head.update(mart_properties)
+
+    def __create_biomart_header_xml(self, mart_properties):
+        """
+        Create the biomart header with given properties
+
+        :param dict mart_properties: The fields and values for the header 
+
+        :return: The biomart header as XML
+        :rtype: ElementTree.Element
+        """
+        # XML header will be added before query is sent
+        biomart_header = ElementTree.Element("Query")
+        biomart_header.attrib.update(mart_properties)
+        return biomart_header
+
+    def __add_attribute(self, parent, attribute_name, attribute_value, name="Attribute"):
+        """
+        Adds an attribute to the ElementTree SubElement
+
+        :param ElementTree parent: The parent element (which is getting modified)
+        :param str attribute_name: The name of the attribute
+        :param str attribute_value: The value of the attribute
+        :param str name: The name of the XML field (default: Attribute)
+
+        :return: The SubElement with attribute
+        :rtype: ElementTree.SubElement
+        """
+        element = ElementTree.SubElement(parent, name)
+        element.set(attribute_name, attribute_value)
+        return element
+
+    def __add_filter(self, parent, filter_id, id, filter_value, value, name="Filter"):
+        """
+        Adds a filter to the ElementTree SubElement
+
+        :param ElementTree parent: The parent element (which is getting modified)
+        :param str filter_id: The name of the filter name field
+        :param str id: The id of the filter
+        :param str filter_value: The name of the filter value field
+        :param str value: The value of the filter
+        :param str name: The name of the XML field (default: Attribute)
+
+        :return: The SubElement with attribute
+        :rtype: ElementTree.SubElement
+        """
+        element = ElementTree.SubElement(parent, name)
+        element.set(filter_id, id)
+        element.set(filter_value, value)
+        return element
+
+    def __search_for_resources(self, xml_root):
+        """
+        Perform search (GET) using the given XML as query value
+
+        :param ElementTree Element xml_root: The XML of the query
+
+        :return: The found resources as data frame
+        :rtype: pandas.core.frame.DataFrame
+        """
+        f = io.BytesIO()
+        et = ElementTree.ElementTree(xml_root)
+        et.write(f, encoding="UTF-8", xml_declaration=True)
+        response = self.__perform_request(self.biomart_url, {"query": f.getvalue().decode("utf8")})
+        result = pd.read_csv(io.StringIO(response.content.decode('utf-8')), delimiter='\t')
+        return result
+
+    def __chunks(self, lst, n):
+        for i in range(0, len(lst), n):
+            yield lst[i:i + n]
+
+    def __perform_request(self, url, params):
+        """
+        Perform a request (GET) on the given url and parameters. 
+        Request will be retried three times on specified errors.
+
+        :return: The response
+        :rtype: request.response
+        """
+        retry_strategy = Retry(
+            total=3,
+            status_forcelist=[429, 500, 502, 503, 504],
+            allowed_methods=["GET"],
+            backoff_factor=3
+        )
+        adapter = HTTPAdapter(max_retries=retry_strategy)
+        request = requests.Session()
+        request.mount("https://", adapter)
+        response = request.get(url, params=params)
+        request.close()
+        return response
+
+    def list_archives(self):
+        """
+        Fetches the available Ensembl archives from the ensembl website
+
+        :return: The available Ensembl archives
+        :rtype: pandas.core.frame.DataFrame
+        """
+        html_text = requests.get(self.biomart_archive_url).text
+        soup = BeautifulSoup(html_text, 'html.parser')
+
+        archives = []
+        for archive in soup.find_all('a', string=re.compile(r'http[s]?://.*ensembl\\.org|[A-Z][a-z]{2} [0-9]{4}')):
+            url = archive['href']
+            version, date = archive.contents[0].split(':')
+            archives.append([version, url, date])
+
+        return pd.DataFrame(archives, columns=['name', 'url', 'date'])
+
+    def get_marts(self):
+        """
+        Fetches the mart registry with information on available marts
+
+        :return: The available marts for this server
+        :rtype: pandas.core.frame.DataFrame
+        """
+        registry = self.__perform_request(self.biomart_url, {"type": "registry"})
+        tree = ElementTree.fromstring(registry.content.decode('utf-8'))
+        data = []
+        for registry in tree:
+            data.append([*registry.attrib.values()])
+        df = pd.DataFrame.from_dict(data)
+        df.columns = [*registry.attrib.keys()]
+        return df
+
+    def get_datasets(self, mart_name):
+        """
+        Fetches available datasets for a given mart name
+
+        :param str mart_name: The name of the mart (e.g. ENSEMBL_MART_ENSEMBL)
+
+        :return: The available datasets for this mart
+        :rtype: pandas.core.frame.DataFrame
+        """
+        datasets = self.__perform_request(self.biomart_url, {"type": "datasets", "mart": mart_name})
+        df = pd.read_csv(io.StringIO(
+            datasets.content.decode('utf-8')), delimiter='\t', header=None)
+        df_slice = df.iloc[:, [1, 2, 4, 7, 8]]
+        df_slice.dropna(how='all', inplace=True)
+        df_slice.columns = ['dataset_id', 'dataset_name',
+                            'short_name', 'interface', 'date']
+        return df_slice
+
+    def get_dataset_attributes(self, dataset_name):
+        """
+        Fetches available attributes for a given dataset of a mart
+
+        :param str dataset_name: The name of the dataset
+
+        :return: The available attributes
+        :rtype: pandas.core.frame.DataFrame
+        """
+        attributes = self.__perform_request(self.biomart_url, {"type": "attributes", "dataset": dataset_name})
+        df = pd.read_csv(io.StringIO(
+            attributes.content.decode('utf-8')), delimiter='\t')
+        df_part = df[df.columns[:3]]
+        df_part.columns = ['attribute_id', 'attribute_name', 'description']
+        return df_part
+
+    def get_dataset_filters(self, dataset_name):
+        """
+        Fetches available filters for a given dataset of a mart
+
+        :param str dataset_name: The name of the dataset
+
+        :return: The available filters
+        :rtype: pandas.core.frame.DataFrame
+        """
+        filters = self.__perform_request(self.biomart_url, {"type": "filters", "dataset": dataset_name})
+        df = pd.read_csv(io.StringIO(
+            filters.content.decode('utf-8')), delimiter='\t')
+        df_part = df[df.columns[:-2]]
+        df_part.columns = ['filter_id', 'filter_name', 'values',
+                        'description', 'type', 'filter_type', 'operator']
+        return df_part
+
+    def get_attribute_name_for_id(self, attributes, attribute_id):
+        """
+        Fetches the attribute name for an attribute id for a given dataset of a mart
+
+        :param pandas.core.frame.DataFrame attributes: The available dataset attributes
+        :param str attribute_id: The id of the attribute
+
+        :return: The corresponding attribute name
+        :rtype: str
+        """
+        return attributes.loc[attributes['attribute_id'] == attribute_id, 'attribute_name'].iloc[0]
+
+    def get_attribute_id_for_name(self, attributes, attribute_name):
+        """
+        Fetches the attribute id for an attribute name for a given dataset of a mart
+
+        :param str dataset_name: The name of the dataset
+        :param pandas.core.frame.DataFrame attributes: The available dataset attributes
+        :param str attribute_name: The name of the attribute
+
+        :return: The corresponding attribute id
+        :rtype: str
+        """
+        return attributes.loc[attributes['attribute_name'] == attribute_name, 'attribute_id'].iloc[0]
 
     def get_product_sequence(self, product_id, **kwargs):
         """
         Fetches product (i.e. protein) sequence for the given id
 
         :param str product_id: The id to be queried
-        :keyword type: Assumes given ID from type found in :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`, default is
-                       ensembl_peptide_id
+        :keyword type: Assumes given ID from type found in :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`, default is ensembl_peptide_id
         :type type: :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`
         :keyword str _db: Can override MartsAdapter default db ("hsapiens_gene_ensembl")
         :keyword str _dataset: Specifies the query dbs dataset if default is not wanted ("gene_ensembl_config")
@@ -74,40 +287,55 @@ def get_product_sequence(self, product_id, **kwargs):
         :return: The requested sequence
         :rtype: str
         """
-
-        _db = kwargs.get("_db", "hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
-
-        query_filter = "ensembl_peptide_id"
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        attributes = {"peptide": "",
+                      EnsemblMartAttributes.EXTERNAL_GENE_NAME.value: ""}
+
+        with_version = '.' in product_id
+        query_filter = EnsemblMartAttributes.ENSEMBL_PEPTIDE_ID_VERSION.value if with_version else EnsemblMartAttributes.ENSEMBL_PEPTIDE_ID.value
         if "type" in kwargs:
-            query_id = kwargs["type"]
             if kwargs["type"] == EIdentifierTypes.REFSEQ:
-                query_filter = "refseq_peptide"
+                query_filter = EnsemblMartAttributes.REFSEQ_PEPTIDE.value
             elif kwargs["type"] == EIdentifierTypes.PREDREFSEQ:
-                query_filter = "refseq_peptide_predicted"
+                query_filter = EnsemblMartAttributes.REFSEQ_PEPTIDE_PREDICTED.value
             elif kwargs["type"] == EIdentifierTypes.ENSEMBL:
-                query_filter = "ensembl_peptide_id"
+                pass
             else:
-                logging.warning("Could not infer the origin of product id " + str(product_id))
+                logging.warning(
+                    "Could not infer the origin of product id " + str(product_id))
                 return None
 
         if product_id in self.sequence_proxy:
             return self.sequence_proxy[product_id]
 
-        rq_n = self.biomart_head%(_db, _dataset) \
-            + self.biomart_filter%(query_filter, str(product_id))  \
-            + self.biomart_attribute%("peptide")  \
-            + self.biomart_attribute%("external_gene_name")  \
-            + self.biomart_tail
-
-        tsvreader = csv.DictReader((urllib.request.urlopen(self.biomart_url +
-                                                          urllib.parse.quote(rq_n))).read().decode('utf-8').splitlines(), dialect='excel-tab')
-        tsvselect = [x for x in tsvreader]
-        if not tsvselect:
-            logging.warning("There seems to be no Proteinsequence for " + str(product_id))
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        self.__add_filter(dataset, "name", query_filter,
+                          "value", str(product_id))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
+
+        result = self.__search_for_resources(root)
+
+        if result.empty:
+            logging.warning(
+                "There seems to be no Protein sequence for " + str(product_id))
             return None
-        self.sequence_proxy[product_id] = tsvselect[0]["Peptide"][:-1] if tsvselect[0]["Peptide"].endswith('*')\
-            else tsvselect[0]["Peptide"]
+
+        sequence = result.at[0, attributes["peptide"]]
+        self.sequence_proxy[product_id] = sequence[:-1] if sequence.endswith('*') else sequence
         return self.sequence_proxy[product_id]
 
     def get_transcript_sequence(self, transcript_id, **kwargs):
@@ -125,43 +353,53 @@ def get_transcript_sequence(self, transcript_id, **kwargs):
         :rtype: str
         """
 
-        _db = kwargs.get("_db", "hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        attributes = {"coding": "", "strand": ""}
 
-        query_filter = "ensembl_transcript_id"
+        with_version = '.' in transcript_id
+        query_filter = EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID_VERSION.value if with_version else EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID.value
         if "type" in kwargs:
-            query_id = kwargs["type"]
             if kwargs["type"] == EIdentifierTypes.REFSEQ:
-                query_filter = "refseq_mrna"
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA.value
             elif kwargs["type"] == EIdentifierTypes.PREDREFSEQ:
-                query_filter = "refseq_mrna_predicted"
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA_PREDICTED.value
             elif kwargs["type"] == EIdentifierTypes.ENSEMBL:
-                query_filter = "ensembl_transcript_id"
+                pass
             else:
-                logging.warning("Could not infer the origin of transcript id " + str(transcript_id))
+                logging.warning(
+                    "Could not infer the origin of transcript id " + str(transcript_id))
                 return None
+        attributes.update({query_filter: ""})
 
         if transcript_id in self.gene_proxy:
             return self.gene_proxy[transcript_id]
 
-        rq_n = self.biomart_head%(_db, _dataset) \
-            + self.biomart_filter%(query_filter, str(transcript_id))  \
-            + self.biomart_attribute%(query_filter)  \
-            + self.biomart_attribute%("coding")  \
-            + self.biomart_attribute%("strand")  \
-            + self.biomart_tail
-
-        tsvreader = csv.DictReader((urllib.request.urlopen(self.biomart_url +
-                                                   urllib.parse.quote(rq_n))).read().decode('utf-8').splitlines(), dialect='excel-tab')
-        tsvselect = [x for x in tsvreader]
-        if not tsvselect:
-            logging.warning("No transcript sequence available for " + str(transcript_id))
-            return None
-        elif 'Sequence unavailable' in tsvselect[0]['Coding sequence']:
-            logging.warning("No transcript sequence available for " + str(transcript_id))
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        self.__add_filter(dataset, "name", query_filter,"value", str(transcript_id))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
+
+        result = self.__search_for_resources(root)
+
+        if result.empty or 'Sequence unavailable' in result.at[0, attributes["coding"]]:
+            logging.warning(
+                "No transcript sequence available for " + str(transcript_id))
             return None
 
-        self.sequence_proxy[transcript_id] = tsvselect[0]['Coding sequence']
+        self.sequence_proxy[transcript_id] = result.at[0, attributes["coding"]]
         return self.sequence_proxy[transcript_id]
 
     def get_transcript_information(self, transcript_id, **kwargs):
@@ -170,7 +408,7 @@ def get_transcript_information(self, transcript_id, **kwargs):
 
         :param str transcript_id: The id to be queried
         :keyword type: Assumes given ID from type found in :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`, default is
-                       ensembl_transcript_id
+                    ensembl_transcript_id
         :type type: :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`
         :keyword str _db: Can override MartsAdapter default db ("hsapiens_gene_ensembl")
         :keyword str _dataset: Specifies the query dbs dataset if default is not wanted ("gene_ensembl_config")
@@ -179,45 +417,56 @@ def get_transcript_information(self, transcript_id, **kwargs):
         :rtype: dict
         """
 
-        _db = kwargs.get("_db", "hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        attributes = {"coding": "", "strand": "",
+                      EnsemblMartAttributes.EXTERNAL_GENE_NAME.value: ""}
 
-        query_filter = "ensembl_transcript_id"
+        with_version = '.' in transcript_id
+        query_filter = EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID_VERSION.value if with_version else EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID.value
         if "type" in kwargs:
             if kwargs["type"] == EIdentifierTypes.REFSEQ:
-                query_filter = "refseq_mrna"
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA.value
             elif kwargs["type"] == EIdentifierTypes.PREDREFSEQ:
-                query_filter = "refseq_mrna_predicted"
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA_PREDICTED.value
             elif kwargs["type"] == EIdentifierTypes.ENSEMBL:
-                query_filter = "ensembl_transcript_id"
+                pass
             else:
-                logging.warning("Could not infer the origin of transcript id " + str(transcript_id))
+                logging.warning(
+                    "Could not infer the origin of transcript id " + str(transcript_id))
                 return None
+        attributes.update({query_filter: ""})
 
         if transcript_id in self.ids_proxy:
             return self.ids_proxy[transcript_id]
 
-        rq_n = self.biomart_head%(_db, _dataset) \
-            + self.biomart_filter%(query_filter, str(transcript_id))  \
-            + self.biomart_attribute%(query_filter)  \
-            + self.biomart_attribute%("coding")  \
-            + self.biomart_attribute%("strand")  \
-            + self.biomart_tail
-
-        tsvreader = csv.DictReader((urllib.request.urlopen(self.biomart_url +
-                                                           urllib.parse.quote(rq_n))).read().decode('utf-8').splitlines(), dialect='excel-tab')
-        tsvselect = [x for x in tsvreader]
-        if not tsvselect:
-            logging.warning("No Information on transcript %s"%transcript_id)
-            return None
-        elif 'Sequence unavailable' in tsvselect[0]['Coding sequence']:
-            logging.warning("No transcript sequence available for " + str(transcript_id))
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        self.__add_filter(dataset, "name", query_filter,"value", str(transcript_id))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
+
+        result = self.__search_for_resources(root)
+
+        if result.empty or 'Sequence unavailable' in result.at[0, attributes["coding"]]:
+            logging.warning(
+                "No information available on transcript " + str(transcript_id))
             return None
 
-        self.ids_proxy[transcript_id] = {EAdapterFields.SEQ: tsvselect[0]['Coding sequence'],
-                                                  EAdapterFields.GENE: tsvselect[0].get('Associated Gene Name', ""),
-                                                  EAdapterFields.STRAND: "-" if int(tsvselect[0]['Strand']) < 0
-                                                  else "+"}
+        self.ids_proxy[transcript_id] = {EAdapterFields.SEQ: result.at[0, attributes["coding"]],
+                                        EAdapterFields.GENE: result.at[0, attributes[EnsemblMartAttributes.EXTERNAL_GENE_NAME.value]],
+                                        EAdapterFields.STRAND: "-" if int(result.at[0, attributes['strand']]) < 0 else "+"}
         return self.ids_proxy[transcript_id]
 
     def get_transcript_position(self, transcript_id, start, stop, **kwargs):
@@ -229,7 +478,7 @@ def get_transcript_position(self, transcript_id, start, stop, **kwargs):
         :param int start: First genomic position to be mapped
         :param int stop: Last genomic position to be mapped
         :keyword type: Assumes given ID from type found in :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`, default is
-                       ensembl_transcript_id
+                    ensembl_transcript_id
         :type type: :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`
         :keyword str _db: Can override MartsAdapter default db ("hsapiens_gene_ensembl")
         :keyword str _dataset: Specifies the query dbs dataset if default is not wanted ("gene_ensembl_config")
@@ -237,68 +486,79 @@ def get_transcript_position(self, transcript_id, start, stop, **kwargs):
         :return: A tuple of the mapped positions start, stop
         :rtype: int
         """
-        # ma = MartsAdapter(biomart="http://grch37.ensembl.org")
-        # print ma.get_transcript_position('17953929', '17953943', 'ENST00000361221')
-        # (1674, 1688)
         try:
             x = int(start)
             y = int(stop)
         except Exception as e:
-            logging.warning(','.join([str(start), str(stop)]) + ' does not seem to be a genomic position.')
+            logging.warning(
+                ','.join([str(start), str(stop)]) + ' does not seem to be a genomic position.')
             return None
 
-        _db = kwargs.get("_db", "hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        attributes = {"exon_chrom_start": "", "exon_chrom_end": "",
+                      "strand": "", "cds_start": "", "cds_end": ""}
 
-        query_filter = "ensembl_transcript_id"
+        with_version = '.' in transcript_id
+        query_filter = EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID_VERSION.value if with_version else EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID.value
         if "type" in kwargs:
             if kwargs["type"] == EIdentifierTypes.REFSEQ:
-                query_filter = "refseq_mrna"
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA.value
             elif kwargs["type"] == EIdentifierTypes.PREDREFSEQ:
-                query_filter = "refseq_mrna_predicted"
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA_PREDICTED.value
             elif kwargs["type"] == EIdentifierTypes.ENSEMBL:
-                query_filter = "ensembl_transcript_id"
+                pass
             else:
-                logging.warning("Could not infer the origin of transcript id " + str(transcript_id))
+                logging.warning(
+                    "Could not infer the origin of transcript id " + str(transcript_id))
                 return None
+        attributes.update({query_filter: ""})
 
         if str(start) + str(stop) + transcript_id in self.gene_proxy:
             return self.gene_proxy[str(start) + str(stop) + transcript_id]
 
-        rq_n = self.biomart_head%(_db, _dataset) \
-            + self.biomart_filter%(query_filter, str(transcript_id))  \
-            + self.biomart_attribute%("exon_chrom_start")  \
-            + self.biomart_attribute%("exon_chrom_end")  \
-            + self.biomart_attribute%("strand")  \
-            + self.biomart_attribute%("cds_start")  \
-            + self.biomart_attribute%("cds_end")  \
-            + self.biomart_tail
-
-        tsvreader = csv.DictReader((urllib.request.urlopen(self.biomart_url +
-                                                    urllib.parse.quote(rq_n)).read()).decode('utf-8').splitlines(), dialect='excel-tab')
-        exons = [ex for ex in tsvreader if ex["CDS start"] and ex["CDS end"]]
-        cds = [dict([k, int(v)] for k, v in e.items()) for e in exons] # cast to int
-        cds = sorted(cds, key=itemgetter("CDS start")) #sort by CDS Start(position in the CDS)
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        self.__add_filter(dataset, "name", query_filter,
+                          "value", str(transcript_id))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
 
-        cds_sum = 0
-        if not cds:
-            logging.warning(str(transcript_id) + ' does not seem to have exons mapped.')
+        result = self.__search_for_resources(root)
+
+        if result.empty:
+            logging.warning(
+                "No information available on transcript " + str(transcript_id))
             return None
 
-        for e in cds:
-            sc = e["CDS start"]
-            ec = e["CDS end"]
-            if not sc or not ec:
-                continue
-            se = e["Exon region start (bp)"]
-            ee = e["Exon region end (bp)"]
+        # filter out results without CDS annotation, sort by CDS Start(position in the CDS)
+        result_cds = result[result[attributes["cds_start"]
+                                   ].notnull() & result[attributes["cds_end"]]]
+        result_sorted = result_cds.sort_values(by=[attributes["cds_start"]])
+
+        cds_sum = 0
+        for index, row in result_sorted.iterrows():
+            sc = row[attributes["cds_start"]]
+            ec = row[attributes["cds_end"]]
+            se = row[attributes["exon_chrom_start"]]
+            ee = row[attributes["exon_chrom_end"]]
 
             if not cds_sum < sc < ec:
-                logging.warning("unable to follow the CDS, aborting genome-positional lookup in transcript!")
-                logging.warning(exons)
-                logging.warning(cds)
+                logging.warning(
+                    "Unable to follow the CDS, aborting genome-positional lookup in transcript!")
                 return None
-                #after sorting and filtering if this occurs points to corrupt data in mart
+                # after sorting and filtering if this occurs points to corrupt data in mart
 
             if x in range(se, ee + 1):
                 if not y in range(se, ee + 1):
@@ -306,8 +566,8 @@ def get_transcript_position(self, transcript_id, start, stop, **kwargs):
                                     ' spans more than one exon, aborting genome-positional lookup in transcript!')
                     return None
                 else:
-                    #strand dependent!!!
-                    if e["Strand"] < 0:  # reverse strand!!!
+                    # strand dependent!!!
+                    if row[attributes["strand"]] < 0:  # reverse strand!!!
                         self.gene_proxy[str(start) + str(stop) + transcript_id] =\
                             (ee - x + 1 + cds_sum, ee - y + 1 + cds_sum)
                     else:  # forward strand!!!
@@ -317,14 +577,15 @@ def get_transcript_position(self, transcript_id, start, stop, **kwargs):
             else:
                 cds_sum = ec
 
-        logging.warning(','.join([str(start), str(stop)]) + ' seems to be outside of the exons boundaries.')
+        logging.warning(','.join([str(start), str(stop)]) +
+                        ' seems to be outside of the exons boundaries.')
         return None
 
-    def get_gene_by_position(self, chrom, start, stop, **kwargs):
+    def get_gene_by_position(self, chromosome, start, stop, **kwargs):
         """
         Fetches the gene name for given chromosomal location
 
-        :param int chrom: Integer value of the chromosome in question
+        :param int chromosome: Integer value of the chromosome in question
         :param int start: Integer value of the variation start position on given chromosome
         :param int stop: Integer value of the variation stop position on given chromosome
         :keyword str _db: Can override MartsAdapter default db ("hsapiens_gene_ensembl")
@@ -333,36 +594,49 @@ def get_gene_by_position(self, chrom, start, stop, **kwargs):
         :return: The respective gene name, i.e. the first one reported
         :rtype: str
         """
-        if str(chrom) + str(start) + str(stop) in self.gene_proxy:
-            return self.gene_proxy[str(chrom) + str(start) + str(stop)]
-
-        _db = kwargs.get("_db", "hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
-
-        rq_n = self.biomart_head%(_db, _dataset) \
-            + self.biomart_filter%("chromosome_name", str(chrom))  \
-            + self.biomart_filter%("start", str(start))  \
-            + self.biomart_filter%("end", str(stop))  \
-            + self.biomart_attribute%("external_gene_name")  \
-            + self.biomart_tail
-
-        tsvreader = csv.DictReader((urllib.request.urlopen(self.biomart_url +
-                                                    urllib.parse.quote(rq_n)).read()).decode('utf-8').splitlines(), dialect='excel-tab')
-        tsvselect = [x for x in tsvreader]
-        if tsvselect and tsvselect[0]:
-            self.gene_proxy[str(chrom) + str(start) + str(stop)] = tsvselect[0]['Gene name']
-            return self.gene_proxy[str(chrom) + str(start) + str(stop)]
-        else:
-            logging.warning(','.join([str(chrom), str(start), str(stop)]) + ' does not denote a known gene location')
-            return ''
+        if str(chromosome) + str(start) + str(stop) in self.gene_proxy:
+            return self.gene_proxy[str(chromosome) + str(start) + str(stop)]
+
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        filters = {"chromosome_name": chromosome, "start": start, "end": stop}
+        attributes = {EnsemblMartAttributes.EXTERNAL_GENE_NAME.value: ""}
+
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        for key, value in filters.items():
+            self.__add_filter(dataset, "name", key, "value", str(value))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
+
+        result = self.__search_for_resources(root)
+        if result.empty:
+            logging.warning(
+                "{} does not denote a known gene location'} ".format(','.join([str(chromosome), str(start), str(stop)])))
+            return None
+
+        self.gene_proxy[str(chromosome) + str(start) + str(stop)
+                        ] = result.at[0, attributes['external_gene_name']]
+        return self.gene_proxy[str(chromosome) + str(start) + str(stop)]
 
-    def get_transcript_information_from_protein_id(self, product_id, **kwargs):
+    def get_transcript_information_from_protein_id(self, protein_id, **kwargs):
         """
-        Fetches transcript sequence for the given id
+        Fetches transcript sequence for the given protein id
 
         :param str product_id: The id to be queried
         :keyword type: Assumes given ID from type found in :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`, default is
-                       ensembl_peptide_id
+                    ensembl_peptide_id
         :type type: :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`
         :keyword str _db: Can override MartsAdapter default db ("hsapiens_gene_ensembl")
         :keyword str _dataset: Specifies the query dbs dataset if default is not wanted ("gene_ensembl_config")
@@ -370,358 +644,363 @@ def get_transcript_information_from_protein_id(self, product_id, **kwargs):
         :rtype: list(dict)
         """
 
-        _db = kwargs.get("_db", "hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        attributes = {
+            "coding": "", EnsemblMartAttributes.EXTERNAL_GENE_NAME.value: "", "strand": ""}
 
-        query_filter = "ensembl_peptide_id"
+        with_version = '.' in protein_id
+        query_filter = EnsemblMartAttributes.ENSEMBL_PEPTIDE_ID_VERSION.value if with_version else EnsemblMartAttributes.ENSEMBL_PEPTIDE_ID.value
         if "type" in kwargs:
             if kwargs["type"] == EIdentifierTypes.REFSEQ:
-                query_filter = "refseq_peptide"
+                query_filter = EnsemblMartAttributes.REFSEQ_PEPTIDE.value
             elif kwargs["type"] == EIdentifierTypes.PREDREFSEQ:
-                query_filter = "refseq_peptide_predicted"
+                query_filter = EnsemblMartAttributes.REFSEQ_PEPTIDE_PREDICTED.value
             elif kwargs["type"] == EIdentifierTypes.ENSEMBL:
-                query_filter = "ensembl_peptide_id"
+                pass
             else:
-                logging.warning("Could not infer the origin of product id " + str(product_id))
+                logging.warning(
+                    "Could not infer the origin of product id " + str(protein_id))
                 return None
 
-        if product_id in self.ids_proxy:
-            return self.ids_proxy[product_id]
-
-        rq_n = self.biomart_head%(_db, _dataset) \
-               + self.biomart_filter%(query_filter, str(product_id)) \
-               + self.biomart_attribute%(query_filter) \
-               + self.biomart_attribute%("coding") \
-               + self.biomart_attribute%("external_gene_id") \
-               + self.biomart_attribute%("strand") \
-               + self.biomart_tail
-
-        tsvreader = csv.DictReader(urllib.request.urlopen(self.biomart_url +
-                                                          urllib.parse.quote(rq_n)).read().decode('utf-8').splitlines(), dialect='excel-tab')
-        tsvselect = [x for x in tsvreader]
-        if not tsvselect:
-            warnings.warn("No entry found for id %s"%product_id)
+        if protein_id in self.ids_proxy:
+            return self.ids_proxy[protein_id]
+
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        self.__add_filter(dataset, "name", query_filter,
+                        "value", str(protein_id))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
+
+        result = self.__search_for_resources(root)
+
+        if result.empty:
+            warnings.warn("No entry found for id %s" % protein_id)
             return None
 
-        self.ids_proxy[product_id] = {EAdapterFields.SEQ: tsvselect[0]['Coding sequence'],
-                                             EAdapterFields.GENE: tsvselect[0]['Associated Gene Name'],
-                                             EAdapterFields.STRAND: "-" if int(tsvselect[0]['Strand']) < 0
-                                             else "+"}
-        return self.ids_proxy[product_id]
+        self.ids_proxy[protein_id] = {EAdapterFields.SEQ: result.at[0, attributes["coding"]],
+                                    EAdapterFields.GENE: result.at[0, attributes[EnsemblMartAttributes.EXTERNAL_GENE_NAME.value]],
+                                    EAdapterFields.STRAND: "-" if int(result.at[0, attributes['strand']]) < 0 else "+"}
+        return self.ids_proxy[protein_id]
 
-    def get_variant_id_from_protein_id(self, transcript_id, **kwargs):
+    def get_variants_from_transcript_id(self, transcript_id, **kwargs):
         """
-        Returns all information needed to instantiate a variation
+        Returns all information needed to instantiate a variation based on given transcript id
 
         :param str transcript_id: The id to be queried
         :keyword type: assumes given ID from type found in :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`, default is
-                       ensembl_transcript_id
+                    ensembl_transcript_id
         :type type: :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`
         :keyword str _db: can override MartsAdapter default db ("hsapiens_gene_ensembl")
         :keyword str _dataset: specifies the query dbs dataset if default is not wanted ("gene_ensembl_config")
 
         :return: Containing all information needed for a variant initialization
-        :rtype: list(dict)
+        :rtype: pandas.core.frame.DataFrame
         """
-        _db = kwargs.get("_db", "hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
-
-        query_filter = "ensembl_peptide_id"
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        filters = {"germ_line_variation_source": "dbSNP"}
+        attributes = {EnsemblMartAttributes.ENSEMBL_GENE_ID.value: "", "variation_name": "", "chromosome_name": "",
+                      "chromosome_start": "", "chromosome_end": "", "allele": "", "snp_chromosome_strand": "", "peptide_location": ""}
+
+        with_version = '.' in transcript_id
+        query_filter = EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID_VERSION.value if with_version else EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID.value
         if "type" in kwargs:
             if kwargs["type"] == EIdentifierTypes.REFSEQ:
-                query_filter = "refseq_mrna"
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA.value
             elif kwargs["type"] == EIdentifierTypes.PREDREFSEQ:
-                query_filter = "refseq_mrna_predicted"
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA_PREDICTED.value
             elif kwargs["type"] == EIdentifierTypes.ENSEMBL:
-                query_filter = "ensembl_transcript_id"
+                pass
             else:
-                logging.warning("Could not infer the origin of transcript id " + str(transcript_id))
+                logging.warning(
+                    "Could not infer the origin of transcript id " + str(transcript_id))
                 return None
+        filters.update({query_filter: transcript_id})
+        attributes.update({query_filter: ""})
+
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        for key, value in filters.items():
+            self.__add_filter(dataset, "name", key, "value", str(value))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
 
-        rq_n = self.biomart_head%(_db, _dataset) \
-               + self.biomart_filter%(query_filter, str(transcript_id)) \
-               + self.biomart_filter%("germ_line_variation_source", "dbSNP") \
-               + self.biomart_attribute%("ensembl_gene_id") \
-               + self.biomart_attribute%("variation_name") \
-               + self.biomart_attribute%("snp_chromosome_name") \
-               + self.biomart_attribute%("chromosome_location") \
-               + self.biomart_attribute%("allele") \
-               + self.biomart_attribute%("snp_strand") \
-               + self.biomart_attribute%("peptide_location") \
-               + self.biomart_tail
-        #tsvreader = csv.DictReader(urllib2.urlopen(self.new_biomart_url+urllib2.quote(rq_n)).read().splitlines(), dialect='excel-tab') #what? brachvogel?
-        tsvreader = csv.DictReader(urllib.request.urlopen(self.biomart_url +
-                                                          urllib.parse.quote(rq_n)).read().decode('utf-8').splitlines(), dialect='excel-tab')
-        tsvselect = [x for x in tsvreader]
-        if not tsvselect:
-            warnings.warn("No entry found for id %s"%transcript_id)
+        result = self.__search_for_resources(root)
+        if result.empty:
+            warnings.warn("No entry found for id %s" % transcript_id)
             return None
 
-        return tsvselect
+        return result
 
-    def get_ensembl_ids_from_id(self, gene_id, **kwargs):
+    def get_ensembl_ids_from_gene(self, gene_id, **kwargs):
         """
-        Returns a list of gene-transcript-protein ids from some sort of id
+        Returns a list of gene-transcript-protein ids from gene name or id
 
         :param str gene_id: The id to be queried
         :keyword type: Assumes given ID from type found in list of :func:`~epytope.IO.ADBAdapter.EIdentifierTypes` ,
-                       default is gene name
+                    default is gene name
         :type type: :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`
         :keyword str _db: can override MartsAdapter default db ("hsapiens_gene_ensembl")
         :keyword str _dataset: specifies the query dbs dataset if default is not wanted ("gene_ensembl_config")
 
         :return: Containing information about the corresponding (linked) entries.
-        :rtype: list(dict)
+        :rtype: dict
         """
-        _db = kwargs.get("_db","hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
-
-        query_filter = "external_gene_name"
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        attributes = {"strand": "", EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID.value: "",
+                      EnsemblMartAttributes.ENSEMBL_PEPTIDE_ID.value: ""}
+
+        with_version = '.' in gene_id
+        query_filter = EnsemblMartAttributes.EXTERNAL_GENE_NAME.value
         if "type" in kwargs:
             if kwargs["type"] == EIdentifierTypes.HGNC:
                 query_filter = "hgnc_symbol"
             elif kwargs["type"] == EIdentifierTypes.UNIPROT:
                 query_filter = "uniprot_swissprot"
             elif kwargs["type"] == EIdentifierTypes.GENENAME:
-                query_filter = "external_gene_name"
+                query_filter = EnsemblMartAttributes.EXTERNAL_GENE_NAME.value
             elif kwargs["type"] == EIdentifierTypes.ENSEMBL:
-                query_filter = "ensemble_gene_id"
+                query_filter = EnsemblMartAttributes.ENSEMBL_GENE_ID_VERSION.value if with_version else EnsemblMartAttributes.ENSEMBL_GENE_ID.value
             else:
-                logging.warning("Could not infer the origin of gene id " + str(gene_id))
+                logging.warning(
+                    "Could not infer the origin of gene id " + str(gene_id))
                 return None
+        attributes.update({query_filter: ""})
 
         if gene_id in self.ids_proxy:
             return self.ids_proxy[gene_id]
 
-        rq_n = self.biomart_head%(_db, _dataset) \
-               + self.biomart_filter%(query_filter, str(gene_id)) \
-               + self.biomart_attribute%("ensembl_gene_id") \
-               + self.biomart_attribute%("strand") \
-               + self.biomart_attribute%("ensembl_transcript_id") \
-               + self.biomart_attribute%("ensembl_peptide_id") \
-               + self.biomart_tail
-        tsvreader = csv.DictReader(urllib.request.urlopen(self.biomart_url +
-                                                   urllib.parse.quote(rq_n)).read().decode('utf-8').splitlines(), dialect='excel-tab')
-        tsvselect = [x for x in tsvreader]
-        if not tsvselect:
-            logging.warning("No entry found for id %s"%gene_id)
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        self.__add_filter(dataset, "name", query_filter, "value", str(gene_id))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
+
+        result = self.__search_for_resources(root)
+        if result.empty:
+            logging.warning("No entry found for id %s" % gene_id)
             return None
 
-        self.ids_proxy[gene_id] = [{EAdapterFields.PROTID: gtp.get('Protein ID', ""),
-                                                  EAdapterFields.GENE: gtp.get('Gene ID', ""),
-                                                  EAdapterFields.TRANSID: gtp.get('Transcript ID', ""),
-                                                  EAdapterFields.STRAND: "-" if int(gtp['Strand']) < 0
-                                                  else "+"} for gtp in tsvselect]
+        EnsemblMartAttributes.ENSEMBL_PEPTIDE_ID
+        for index, row in result.iterrows():
+            self.ids_proxy[gene_id] = [{EAdapterFields.PROTID: row[attributes[EnsemblMartAttributes.ENSEMBL_PEPTIDE_ID.value]],
+                                        EAdapterFields.GENE: row[attributes[query_filter]],
+                                        EAdapterFields.TRANSID: row[attributes[EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID.value]],
+                                        EAdapterFields.STRAND: "-" if int(row[attributes['strand']]) < 0
+                                        else "+"}]
         return self.ids_proxy[gene_id]
 
-    #TODO: refactor ... function based on old code
-    def get_all_variant_gene(self, locations, _db="hsapiens_gene_ensembl", _dataset='gene_ensembl_config'):
+    def get_genes_from_location(self, chromosome, start, stop, **kwargs):
         """
         Fetches the important db ids and names for given chromosomal location
 
-        :param int chrom: Integer value of the chromosome in question
+        :param int chromosome: Integer value of the chromosome in question
         :param int start: Integer value of the variation start position on given chromosome
         :param int stop: Integer value of the variation stop position on given chromosome
-        :return: The respective gene name, i.e. the first one reported
+        :return: The respective gene names and identifiers
+        :rtype: pandas.core.frame.DataFrame
+        """
+
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        attributes = {EnsemblMartAttributes.ENSEMBL_GENE_ID.value: "",
+                      "uniprot_gn_symbol": "", EnsemblMartAttributes.EXTERNAL_GENE_NAME.value: ""}
+        filters = {"chromosomal_region": f"{chromosome}:{start}:{stop}"}
+
+        if chromosome + start + stop in self.gene_proxy:
+            return self.gene_proxy[chromosome + start + stop]
+
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        for key, value in filters.items():
+            self.__add_filter(dataset, "name", key, "value", str(value))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
+
+        result = self.__search_for_resources(root)
+        if result.empty:
+            warnings.warn(
+                f"No identifiers found for specified region {chromosome}:{start}:{stop}")
+            return None
+
+        return result
 
+    def get_protein_ids_from_transcripts(self, transcripts, **kwargs):
         """
-        #TODO assert types
-        #<!DOCTYPE Query><Query client="true" processor="TSV" limit="-1" header="1"><Dataset name="hsapiens_gene_ensembl" config="gene_ensembl_config"><Filter name="chromosomal_region" value="1:40367114:40367114,1:40702744:40702744,1:40705023:40705023,1:40771399:40771399,1:40777210:40777210,1:40881015:40881015,1:41235036:41235036,1:42048927:42048927,1:43002232:43002232,1:43308758:43308758,1:43393391:43630154,1:43772617:43772617,1:43772834:43772834" filter_list=""/><Attribute name="uniprot_genename"/></Dataset></Query>
-        #queries = [self.biomart_filter%("uniprot_genename", ','.join(kwargs['genes'][x:x+300])) for x in xrange(0, len(kwargs['genes']), 300)]
-        # if chrom + start + stop in self.gene_proxy:
-        #     return self.gene_proxy[chrom + start + stop]
-        #
-        # rq_n = self.biomart_head \
-        #     + self.biomart_filter%("chromosome_name", str(chrom))  \
-        #     + self.biomart_filter%("start", str(start))  \
-        #     + self.biomart_filter%("end", str(stop))  \
-        #     + self.biomart_attribute%("uniprot_genename")  \
-        #     + self.biomart_tail
-        #
-        # tsvreader = csv.DictReader((urllib2.urlopen(self.biomart_url+urllib2.quote(rq_n)).read()).splitlines(), dialect='excel-tab')
-        # tsvselect = [x for x in tsvreader]
-        # if tsvselect and tsvselect[0]:
-        #     self.gene_proxy[chrom + start + stop] = tsvselect[0]['UniProt Gene Name']
-        #     return tsvselect[0]['UniProt Gene Name']
-        # else:
-        #     logging.warn(','.join([str(chrom), str(start), str(stop)]) + ' does not denote a known gene location')
-        #     return ''
-
-    #TODO: refactor ... function based on old code
-    def get_variant_ids(self, **kwargs):
-        """
-        Fetches the important db ids and names for given gene _or_ chromosomal location. The former is recommended.
-        AResult is a list of dicts with either of the tree combinations:
-            - 'Ensembl Gene ID', 'Ensembl Transcript ID', 'Ensembl Protein ID'
-            - 'RefSeq Protein ID [e.g. NP_001005353]', 'RefSeq mRNA [e.g. NM_001195597]', first triplet
-            - 'RefSeq Predicted Protein ID [e.g. XP_001720922]', 'RefSeq mRNA predicted [e.g. XM_001125684]', first triplet
-        :keyword 'chrom': integer value of the chromosome in question
-        :keyword 'start': integer value of the variation start position on given chromosome
-        :keyword 'stop': integer value of the variation stop position on given chromosome
-        :keyword 'gene': string value of the gene of variation
-        :keyword 'transcript_id': string value of the gene of variation
-        :return: The list of dicts of entries with transcript and protein ids (either NM+NP or XM+XP)
-        """
-        # TODO type assessment
-        _db = kwargs.get("_db","hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
-        ensemble_only = False
-        query = None
-        if len(kwargs) == 4 and 'chrom' in kwargs and 'start' in kwargs and 'stop' in kwargs and 'ensemble_only' in kwargs:
-            ensemble_only = kwargs['ensemble_only']
-            query = self.biomart_filter%("chromosome_name", kwargs['chrom'])  \
-                + self.biomart_filter%("start", kwargs['start'])  \
-                + self.biomart_filter%("end", kwargs['stop'])
-        if len(kwargs) == 3 and 'chrom' in kwargs and 'start' in kwargs and 'stop' in kwargs:
-            query = self.biomart_filter%("chromosome_name", kwargs['chrom'])  \
-                + self.biomart_filter%("start", kwargs['start'])  \
-                + self.biomart_filter%("end", kwargs['stop'])
-        elif len(kwargs) == 2 and 'gene' in kwargs and 'ensemble_only' in kwargs:
-            ensemble_only = kwargs['ensemble_only']
-            query = self.biomart_filter%("uniprot_genename", kwargs['gene'])
-        elif len(kwargs) == 2 and 'transcript_id' in kwargs and 'ensemble_only' in kwargs:
-            ensemble_only = kwargs['ensemble_only']
-            query = self.biomart_filter%("ensembl_transcript_id", kwargs['transcript_id'])
-        elif len(kwargs) == 1 and 'gene' in kwargs:
-            query = self.biomart_filter%("uniprot_genename", kwargs['gene'])
-        else:
-            warnings.warn("wrong arguments to get_variant_ids")
-
-        rq_n = self.biomart_head%(_db, _dataset) \
-            + query \
-            + self.biomart_attribute%("uniprot_genename")  \
-            + self.biomart_attribute%("ensembl_gene_id")  \
-            + self.biomart_attribute%("ensembl_peptide_id")  \
-            + self.biomart_attribute%("ensembl_transcript_id")  \
-            + self.biomart_attribute%("strand")
-        if not ensemble_only:
-            rq_n += self.biomart_attribute%("refseq_mrna")  \
-                + self.biomart_attribute%("refseq_peptide")
-        rq_n += self.biomart_attribute%("uniprot_swissprot") + self.biomart_tail
-
-        tsvreader = csv.DictReader((urllib.request.urlopen(self.biomart_url +
-                                                           urllib.parse.quote(rq_n)).read()).decode('utf-8').splitlines(), dialect='excel-tab')
-        if ensemble_only:
-            result = {x['Ensembl Gene ID']+x['Ensembl Transcript ID']+x['Ensembl Protein ID']: x for x in tsvreader}
-        else:
-            result = {x['Ensembl Gene ID']+x['Ensembl Transcript ID']+x['Ensembl Protein ID']: x for x in tsvreader
-                  if x['RefSeq Protein ID [e.g. NP_001005353]'] and x['RefSeq mRNA [e.g. NM_001195597]']}
-
-        if not ensemble_only:
-            rq_x = self.biomart_head \
-                + query  \
-                + self.biomart_attribute%("uniprot_genename")  \
-                + self.biomart_attribute%("ensembl_gene_id")  \
-                + self.biomart_attribute%("ensembl_peptide_id")  \
-                + self.biomart_attribute%("ensembl_transcript_id")  \
-                + self.biomart_attribute%("refseq_peptide_predicted")  \
-                + self.biomart_attribute%("refseq_mrna_predicted")  \
-                + self.biomart_attribute%("strand")  \
-                + self.biomart_tail
-
-            tsvreader = csv.DictReader((urllib.request.urlopen(self.biomart_url +
-                                                               urllib.parse.quote(rq_x)).read()).decode('utf-8').splitlines(), dialect='excel-tab')
-
-            result2 = {x['Ensembl Gene ID']+x['Ensembl Transcript ID']+x['Ensembl Protein ID']: x for x in tsvreader
-                       if (x['RefSeq Predicted Protein ID [e.g. XP_001720922]'] and x['RefSeq mRNA predicted [e.g. XM_001125684]'])
-                       or (not x['RefSeq Predicted Protein ID [e.g. XP_001720922]'] and not x['RefSeq mRNA predicted [e.g. XM_001125684]'])}
-            result.update(result2)
-
-        g = None
-        for k, v in result.items():
-            if 'uniprot_swissprot' in v:
-                g = v['uniprot_swissprot']
-        self.ids_proxy[g] = list(result.values())
-        return list(result.values())
-
-    #TODO: refactor ... function based on old code
-    def get_all_variant_ids(self, **kwargs):
-        """
-        Fetches the important db ids and names for given gene _or_ chromosomal location. The former is recommended.
-        AResult is a list of dicts with either of the tree combinations:
-            - 'Ensembl Gene ID', 'Ensembl Transcript ID', 'Ensembl Protein ID'
-            - 'RefSeq Protein ID [e.g. NP_001005353]', 'RefSeq mRNA [e.g. NM_001195597]', first triplet
-            - 'RefSeq Predicted Protein ID [e.g. XP_001720922]', 'RefSeq mRNA predicted [e.g. XM_001125684]', first triplet
-        :keyword 'locations': list of locations as triplets of integer values representing (chrom, start, stop)
-        :keyword 'genes': list of genes as string value of the genes of variation
-        :return: The list of dicts of entries with transcript and protein ids (either NM+NP or XM+XP)
-        """
-        _db = kwargs.get("_db","hsapiens_gene_ensembl")
-        _dataset = kwargs.get("_dataset", "gene_ensembl_config")
-        end_result = dict()
-        # TODO type assessment
-        ensemble_only = False
-        query = None
-        if 'ensemble_only' in kwargs:
-            ensemble_only = kwargs['ensemble_only']
-        if 'locations' in kwargs:
-            pass
-            #TODO
-            # query = self.biomart_filter%("chromosome_name", kwargs['chrom'])  \
-            #         + self.biomart_filter%("start", kwargs['start'])  \
-            #         + self.biomart_filter%("end", kwargs['stop'])
-        elif 'genes' in kwargs:
-            queries = [self.biomart_filter%("uniprot_genename", ','.join(kwargs['genes'][x:x+250])) for x in range(0, len(kwargs['genes']), 250)]
-            logging.warning('***'+self.biomart_filter%("uniprot_genename", ','.join(kwargs['genes'][x:x+250])) for x in range(0, len(kwargs['genes']), 250))
+        Fetches protein identifiers for the given transcript ids
+
+        :param list(str) transcripts: The ids to be queried
+        :keyword type: Assumes given ID from type found in :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`, default is
+                    ensembl_peptide_id
+        :type type: :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`
+        :keyword str _db: Can override MartsAdapter default db ("hsapiens_gene_ensembl")
+        :keyword str _dataset: Specifies the query dbs dataset if default is not wanted ("gene_ensembl_config")
+        :keyword int _max_request_length: Specifies the maximum length of request identifiers, default is 300
+        :return: Data frame with Ensembl/RefSeq/UniProt protein id and the corresponding transcript ID (Ensembl)
+        :rtype: pandas.core.frame.DataFrame
+        """
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        max_request_length = kwargs.get(
+            "_max_request_length", 300)
+        attributes = {EnsemblMartAttributes.ENSEMBL_PEPTIDE_ID.value: "",
+                      EnsemblMartAttributes.REFSEQ_PEPTIDE.value: ""}
+
+        dataset_attributes = self.get_dataset_attributes(_db)
+        attribute_swissprot = "uniprotswissprot" if (
+            "uniprotswissprot" in dataset_attributes.values) else "uniprot_swissprot_accession"
+        attributes.update({attribute_swissprot: ""})
+
+        with_version = '.' in transcripts[0]
+        query_filter = EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID_VERSION.value if with_version else EnsemblMartAttributes.ENSEMBL_TRANSCRIPT_ID.value
+        if "type" in kwargs:
+            if kwargs["type"] == EIdentifierTypes.REFSEQ:
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA.value
+            elif kwargs["type"] == EIdentifierTypes.PREDREFSEQ:
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA_PREDICTED.value
+            elif kwargs["type"] == EIdentifierTypes.ENSEMBL:
+                pass
+            else:
+                logging.warning(
+                    f"Could not infer the origin of specified transcript ids {transcripts}")
+                return None
+        attributes.update({query_filter: ""})
+
+        if len(transcripts) > max_request_length:
+            transcripts_split = list(self.__chunks(
+                transcripts, max_request_length))
         else:
-            logging.warning("wrong arguments to get_variant_ids")
-        for query in queries:
-            rq_n = self.biomart_head%(_db,_dataset) \
-                + query \
-                + self.biomart_attribute%("uniprot_genename")  \
-                + self.biomart_attribute%("ensembl_gene_id")  \
-                + self.biomart_attribute%("ensembl_peptide_id")  \
-                + self.biomart_attribute%("ensembl_transcript_id")  \
-                + self.biomart_attribute%("strand")
-            if not ensemble_only:
-                rq_n += self.biomart_attribute%("refseq_mrna")  \
-                    + self.biomart_attribute%("refseq_peptide")
-            rq_n += self.biomart_tail
-            # rq_n += self.biomart_attribute%("uniprot_swissprot") + self.biomart_tail
-
-            # logging.warning(rq_n)
+            transcripts_split = [transcripts]
 
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
             try:
-                tsvreader = csv.DictReader((urllib.request.urlopen(self.biomart_url +
-                                                                   urllib.parse.quote(rq_n)).read()).decode('utf-8').splitlines(), dialect='excel-tab')
-                if ensemble_only:
-                    result = {x['Ensembl Gene ID']+x['Ensembl Transcript ID']+x['Ensembl Protein ID']: x for x in tsvreader}
-                else:
-                    result = {x['Ensembl Gene ID']+x['Ensembl Transcript ID']+x['Ensembl Protein ID']: x for x in tsvreader
-                          if x['RefSeq Protein ID [e.g. NP_001005353]'] and x['RefSeq mRNA [e.g. NM_001195597]']}
-                end_result.update(result)
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
             except:
-                logging.error('Bad Mart Query: '+rq_n)
-
-            if not ensemble_only:
-                rq_x = self.biomart_head%(_db, _dataset) \
-                    + query  \
-                    + self.biomart_attribute%("uniprot_genename")  \
-                    + self.biomart_attribute%("ensembl_gene_id")  \
-                    + self.biomart_attribute%("ensembl_peptide_id")  \
-                    + self.biomart_attribute%("ensembl_transcript_id")  \
-                    + self.biomart_attribute%("refseq_peptide_predicted")  \
-                    + self.biomart_attribute%("refseq_mrna_predicted")  \
-                    + self.biomart_attribute%("strand")  \
-                    + self.biomart_tail
-
-                try:
-                    tsvreader = csv.DictReader((urllib.request.urlopen(self.biomart_url +
-                                                                       urllib.parse.quote(rq_x)).read().decode('utf-8')).splitlines(), dialect='excel-tab')
-
-                    for x in tsvreader:
-                        if (x['RefSeq Predicted Protein ID [e.g. XP_001720922]'] and x['RefSeq mRNA predicted [e.g. XM_001125684]']):
-                            end_result.setdefault(x['Ensembl Gene ID']+x['Ensembl Transcript ID']+x['Ensembl Protein ID'], x)
-                    # result2 = {x['Ensembl Gene ID']+x['Ensembl Transcript ID']+x['Ensembl Protein ID']: x for x in tsvreader
-                    #            if (x['RefSeq Predicted Protein ID [e.g. XP_001720922]'] and x['RefSeq mRNA predicted [e.g. XM_001125684]'])
-                    #     this line is a troublemaker and does not help       or (not x['RefSeq Predicted Protein ID [e.g. XP_001720922]'] and not x['RefSeq mRNA predicted [e.g. XM_001125684]'])}
-                    # end_result.setdefault(result2)
-                except:
-                    logging.error('Bad Mart Query: '+rq_n)
-
-        # g = None
-        # for k, v in result.iteritems():
-        #     if 'uniprot_swissprot' in v:
-        #         g = v['uniprot_swissprot']
-        # self.ids_proxy[g] = result.values()
-        return list(end_result.values())
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
+
+        # to avoid errors because of too large Request-URI we split up the requests
+        frames = []
+        for t in transcripts_split:
+            added_filters = self.__add_filter(
+                dataset, "name", query_filter, "value", ','.join(t))
+            frames.append(self.__search_for_resources(root))
+            dataset.remove(added_filters)
+
+        result = pd.concat(frames, ignore_index=True)
+
+        if result.empty:
+            warnings.warn(f"No entry found for given identifiers.")
+            return None
+        result.columns = ["ensembl_id", "refseq_id",
+                          "uniprot_id", "transcript_id"]
+
+        return result
+
+    def get_gene_names_from_ids(self, gene_ids, **kwargs):
+        """
+        Returns the gene names for given gene identifiers
+
+        :param list gene_ids: The ids to be queried
+        :type type: :func:`~epytope.IO.ADBAdapter.EIdentifierTypes`
+        :keyword str _db: can override MartsAdapter default db ("hsapiens_gene_ensembl")
+        :keyword str _dataset: specifies the query dbs dataset if default is not wanted ("gene_ensembl_config")
+
+        :return: Data frame with gene name and the given gene identifiers
+        :rtype: pandas.core.frame.DataFrame
+        """
+        _db = kwargs.get(
+            "_db", EnsemblMartAttributes.ENSEMBL_HSAPIENS_DATASET.value)
+        _dataset = kwargs.get(
+            "_dataset", EnsemblMartAttributes.ENSEMBL_GENE_CONFIG.value)
+        attributes = {EnsemblMartAttributes.EXTERNAL_GENE_NAME.value: ""}
+
+        with_version = '.' in gene_ids[0]
+        query_filter = EnsemblMartAttributes.ENSEMBL_GENE_ID_VERSION.value if with_version else EnsemblMartAttributes.ENSEMBL_GENE_ID.value
+
+        if "type" in kwargs:
+            if kwargs["type"] == EIdentifierTypes.REFSEQ:
+                query_filter = EnsemblMartAttributes.REFSEQ_MRNA.value
+        attributes.update({query_filter: ""})
+
+        for gene_id in gene_ids:
+            if gene_id in self.ids_proxy:
+                return self.ids_proxy[gene_id]
+
+        dataset_attributes = self.get_dataset_attributes(_db)
+        root = self.__create_biomart_header_xml(self.biomart_head)
+        dataset = ElementTree.SubElement(root, "Dataset")
+        dataset.attrib.update({"name": _db, "interface": "default"})
+        self.__add_filter(dataset, "name", query_filter,
+                          "value", ','.join(gene_ids))
+        for attribute in attributes:
+            self.__add_attribute(dataset, "name", attribute)
+            try:
+                attribute_name = self.get_attribute_name_for_id(dataset_attributes, attribute)
+                attributes.update({attribute: attribute_name})
+            except:
+                logging.error("Attribute {} not found for dataset {} on {}".format(
+                    attribute, _db, self.biomart_url))
+                sys.exit(1)
+
+        result = self.__search_for_resources(root)
+        if result.empty:
+            logging.warning("No entry found for id %s" % gene_id)
+            return None
+        result.columns = ["gene_name", "gene_id"]
+        return result
diff --git a/setup.py b/setup.py
index c7d4400..8f18a0c 100644
--- a/setup.py
+++ b/setup.py
@@ -111,6 +111,8 @@
             'mhcnuggets',
             'keras<=2.3.1',         # legacy tensorflow required by mhcnuggets resolves to incompatible keras version
             'h5py<=2.10.0',         # mhcnuggets fails to read model with newer versions
+            'requests',
+            'beautifulsoup4',
             ],
 
 )


Test patch:
diff --git a/epytope/test/TestGenerator.py b/epytope/test/TestGenerator.py
index dc8ea17..814c43d 100644
--- a/epytope/test/TestGenerator.py
+++ b/epytope/test/TestGenerator.py
@@ -34,7 +34,7 @@ def setUp(self):
                                         "NM_001114377", 653, 217, "", "")
                                     }, False, True)
 
-        self.db_adapter = MartsAdapter(biomart="http://grch37.ensembl.org/biomart/martservice?query=")
+        self.db_adapter = MartsAdapter(biomart="http://grch37.ensembl.org")
 
     def test__incorp_snp(self):
         ts = list("TESTSEQUENCE")
@@ -265,7 +265,7 @@ def test_heterozygous_variants(self):
     #     self.assertTrue(len(peps - peps_from_prot) == 0)
     #     self.assertTrue(len(peps_from_prot - peps) == 0)
 
-    def test_peptides_from_varaints(self):
+    def test_peptides_from_variants(self):
         coding = {}
         coding['NM_080751'] = MutationSyntax('NM_080751',2629,876,'c.2630C>T','p.Pro877Leu')
         var = Variant('line0',0,20,2621905,'C','T',coding,True,False)
diff --git a/epytope/test/TestIO.py b/epytope/test/TestIO.py
index 3873f11..64644f1 100644
--- a/epytope/test/TestIO.py
+++ b/epytope/test/TestIO.py
@@ -1,6 +1,4 @@
 from unittest import TestCase
-import copy
-
 from epytope.Core import Allele
 from epytope.IO import FileReader
 from epytope.IO.MartsAdapter import MartsAdapter
@@ -9,7 +7,6 @@
 from epytope.IO.UniProtAdapter import UniProtDB
 from epytope.IO.ADBAdapter import ADBAdapter, EAdapterFields, EIdentifierTypes
 import warnings
-import logging
 import os
 import inspect
 import epytope
@@ -35,12 +32,16 @@ def setUp(self):
         self.ano_path = os.path.join(os.path.dirname(inspect.getfile(epytope)), "Data/examples/test_annovar.out")
         self.NP_001005353 = "MASKLLRAVILGPPGSGKGTVCQRIAQNFGLQHLSSGHFLRENIKASTEVGEMAKQYIEKSLLVPDHVITRLMMSELENRRGQHWLLDGFPRTLGQAEALDKICEVDLVISLNIPFETLKDRLSRRWIHPPSGRVYNLDFNPPHVHGIDDVTGEPLVQQEDDKPEAVAARLRQYKDVAKPVIELYKSRGVLHQFSGTETNKIWPYVYTLFSNKITPIQSKEAY"
         self.ENSP00000369497 = "MPIGSKERPTFFEIFKTRCNKADLGPISLNWFEELSSEAPPYNSEPAEESEHKNNNYEPNLFKTPQRKPSYNQLASTPIIFKEQGLTLPLYQSPVKELDKFKLDLGRNVPNSRHKSLRTVKTKMDQADDVSCPLLNSCLSESPVVLQCTHVTPQRDKSVVCGSLFHTPKFVKGRQTPKHISESLGAEVDPDMSWSSSLATPPTLSSTVLIVRNEEASETVFPHDTTANVKSYFSNHDESLKKNDRFIASVTDSENTNQREAASHGFGKTSGNSFKVNSCKDHIGKSMPNVLEDEVYETVVDTSEEDSFSLCFSKCRTKNLQKVRTSKTRKKIFHEANADECEKSKNQVKEKYSFVSEVEPNDTDPLDSNVANQKPFESGSDKISKEVVPSLACEWSQLTLSGLNGAQMEKIPLLHISSCDQNISEKDLLDTENKRKKDFLTSENSLPRISSLPKSEKPLNEETVVNKRDEEQHLESHTDCILAVKQAISGTSPVASSFQGIKKSIFRIRESPKETFNASFSGHMTDPNFKKETEASESGLEIHTVCSQKEDSLCPNLIDNGSWPATTTQNSVALKNAGLISTLKKKTNKFIYAIHDETSYKGKKIPKDQKSELINCSAQFEANAFEAPLTFANADSGLLHSSVKRSCSQNDSEEPTLSLTSSFGTILRKCSRNETCSNNTVISQDLDYKEAKCNKEKLQLFITPEADSLSCLQEGQCENDPKSKKVSDIKEEVLAAACHPVQHSKVEYSDTDFQSQKSLLYDHENASTLILTPTSKDVLSNLVMISRGKESYKMSDKLKGNNYESDVELTKNIPMEKNQDVCALNENYKNVELLPPEKYMRVASPSRKVQFNQNTNLRVIQKNQEETTSISKITVNPDSEELFSDNENNFVFQVANERNNLALGNTKELHETDLTCVNEPIFKNSTMVLYGDTGDKQATQVSIKKDLVYVLAEENKNSVKQHIKMTLGQDLKSDISLNIDKIPEKNNDYMNKWAGLLGPISNHSFGGSFRTASNKEIKLSEHNIKKSKMFFKDIEEQYPTSLACVEIVNTLALDNQKKLSKPQSINTVSAHLQSSVVVSDCKNSHITPQMLFSKQDFNSNHNLTPSQKAEITELSTILEESGSQFEFTQFRKPSYILQKSTFEVPENQMTILKTTSEECRDADLHVIMNAPSIGQVDSSKQFEGTVEIKRKFAGLLKNDCNKSASGYLTDENEVGFRGFYSAHGTKLNVSTEALQKAVKLFSDIENISEETSAEVHPISLSSSKCHDSVVSMFKIENHNDKTVSEKNNKCQLILQNNIEMTTGTFVEEITENYKRNTENEDNKYTAASRNSHNLEFDGSDSSKNDTVCIHKDETDLLFTDQHNICLKLSGQFMKEGNTQIKEDLSDLTFLEVAKAQEACHGNTSNKEQLTATKTEQNIKDFETSDTFFQTASGKNISVAKESFNKIVNFFDQKPEELHNFSLNSELHSDIRKNKMDILSYEETDIVKHKILKESVPVGTGNQLVTFQGQPERDEKIKEPTLLGFHTASGKKVKIAKESLDKVKNLFDEKEQGTSEITSFSHQWAKTLKYREACKDLELACETIEITAAPKCKEMQNSLNNDKNLVSIETVVPPKLLSDNLCRQTENLKTSKSIFLKVKVHENVEKETAKSPATCYTNQSPYSVIENSALAFYTSCSRKTSVSQTSLLEAKKWLREGIFDGQPERINTADYVGNYLYENNSNSTIAENDKNHLSEKQDTYLSNSSMSNSYSYHSDEVYNDSGYLSKNKLDSGIEPVLKNVEDQKNTSFSKVISNVKDANAYPQTVNEDICVEELVTSSSPCKNKNAAIKLSISNSNNFEVGPPAFRIASGKIVCVSHETIKKVKDIFTDSFSKVIKENNENKSKICQTKIMAGCYEALDDSEDILHNSLDNDECSTHSHKVFADIQSEEILQHNQNMSGLEKVSKISPCDVSLETSDICKCSIGKLHKSVSSANTCGIFSTASGKSVQVSDASLQNARQVFSEIEDSTKQVFSKVLFKSNEHSDQLTREENTAIRTPEHLISQKGFSYNVVNSSAFSGFSTASGKQVSILESSLHKVKGVLEEFDLIRTEHSLHYSPTSRQNVSKILPRVDKRNPEHCVNSEMEKTCSKEFKLSNNLNVEGGSSENNHSIKVSPYLSQFQQDKQQLVLGTKVSLVENIHVLGKEQASPKNVKMEIGKTETFSDVPVKTNIEVCSTYSKDSENYFETEAVEIAKAFMEDDELTDSKLPSHATHSLFTCPENEEMVLSNSRIGKRRGEPLILVGEPSIKRNLLNEFDRIIENQEKSLKASKSTPDGTIKDRRLFMHHVSLEPITCVPFRTTKERQEIQNPNFTAPGQEFLSKSHLYEHLTLEKSSSNLAVSGHPFYQVSATRNEKMRHLITTGRPTKVFVPPFKTKSHFHRVEQCVRNINLEENRQKQNIDGHGSDDSKNKINDNEIHQFNKNNSNQAVAVTFTKCEEEPLDLITSLQNARDIQDMRIKKKQRQRVFPQPGSLYLAKTSTLPRISLKAAVGGQVPSACSHKQLYTYGVSKHCIKINSKNAESFQFHTEDYFGKESLWTGKGIQLADGGWLIPSNDGKAGKEEFYRALCDTPGVDPKLISRIWVYNHYRWIIWKLAAMECAFPKEFANRCLSPERVLLQLKYRYDTEIDRSRRSAIKKIMERDDTAAKTLVLCVSDIISLSANISETSSNKTSSADTQKVAIIELTDGWYAVKAQLDPPLLAVLKNGRLTVGQKIILHGAELVGSPDACTPLEAPESLMLKISANSTRPARWYTKLGFFPDPRPFPLPLSSLFSDGGNVGCVDVIIQRAYPIQWMEKTSSGLYIFRNEREEEKEAAKYVEAQQKRLEALFTKIQEEFEEHEENTTKPYLPSRALTRQQVRALQDGAELYEAVKNAADPAYLEGYFSEEQLRALNNHRQMLNDKKQAQIQLEIRKAMESAEQKEQGLSRDVTTVWKLRIVSYSKKEKDSVILSIWRPSSDLYSLLTEGKRYRIYHLATSKSKSKSERANIQLAATKKTQYQQLPVSDEILFQIYQPREPLHFSKFLDPDFQPSCSEVDLIGFVVSVVKKTGLAPFVYLSDECYNLLAIKFWIDLNEDIIKPHMLIAASNLQWRPESKSGLLTLFAGDFSVFSASPKEGHFQETFNKMKNTVENIDILCNEAENKLMHILHANDPKWSTPTKDCTSGPYTAQIIPGTGNKLLMSSPNCEIYYQSPLSLCMAKRKSVSTPVSAQMTSKSCKGEKEIDDQKNCKKRRALDFLSRLPLPPPVSPICTFVSPAAQKAFQPPRSCGTKYETPIKKKELNSPQMTPFKKFNEISLLESNSIADEELALINTQALLSGSTGEKQFISVSESTRTAPTSSEDYLRLKRRCTTSLIKEQESSQASTEECEKNKQDTITTKKYI"
-        self.ENST00000361221 = {0: '', 1: '+', 2: 'ATGGCTTCCTCCAACCCTCCTCCACAGCCTGCCATAGGAGATCAGCTGGTTCCAGGAGTCCCAGGCCCCTCCTCTGAGGCAGAGGACGACCCAGGAGAGGCGTTTGAGTTTGATGACAGTGATGATGAAGAGGACACCAGCGCAGCCCTGGGCGTCCCCAGCCTTGCTCCTGAGAGGGACACAGACCCCCCACTGATCCACTTGGACTCCATCCCTGTCACTGACCCAGACCCAGCAGCTGCTCCACCCGGCACAGGGGTGCCAGCCTGGGTGAGCAATGGGGATGCAGCGGACGCAGCCTTCTCCGGGGCCCGGCACTCCAGCTGGAAGCGGAAGAGTTCCCGTCGCATTGACCGGTTCACTTTCCCCGCCCTGGAAGAGGATGTGATTTATGACGACGTCCCCTGCGAGAGCCCAGATGCGCATCAGCCCGGGGCAGAGAGGAACCTGCTCTACGAGGATGCGCACCGGGCTGGGGCCCCTCGGCAGGCGGAGGACCTAGGCTGGAGCTCCAGTGAGTTCGAGAGCTACAGCGAGGACTCGGGGGAGGAGGCCAAGCCGGAGGTCGAGGTCGAGCCCGCCAAGCACCGAGTGTCCTTCCAGCCCAAGCTTTCTCCAGACCTGACTAGGCTAAAGGAGAGATACGCCAGGACTAAGAGAGACATCTTGGCTTTGAGAGTTGGGGGGAGAGACATGCAGGAGCTGAAGCACAAGTACGATTGTAAGATGACCCAGCTCATGAAGGCCGCCAAGAGCGGGACCAAGGATGGGCTGGAGAAGACACGGATGGCCGTGATGCGCAAAGTCTCCTTCCTGCACAGGAAGGACGTCCTCGGTGACTCGGAGGAGGAGGACATGGGGCTCCTGGAGGTCAGCGTTTCGGACATCAAGCCCCCAGCCCCAGAGCTGGGCCCCATGCCAGAGGGCCTGAGCCCTCAGCAGGTGGTCCGGAGGCATATCCTGGGCTCCATCGTGCAGAGCGAAGGCAGCTACGTGGAGTCTCTGAAGCGGATACTCCAGGACTACCGCAACCCCCTGATGGAGATGGAGCCCAAGGCGCTGAGCGCCCGCAAGTGCCAGGTGGTGTTCTTCCGCGTGAAGGAGATCCTGCACTGCCACTCCATGTTCCAGATCGCCCTGTCCTCCCGCGTGGCTGAGTGGGATTCCACCGAGAAGATCGGGGACCTCTTCGTGGCCTCGTTTTCCAAGTCCATGGTGCTAGATGTGTACAGTGACTACGTGAACAACTTCACCAGTGCCATGTCCATCATCAAGAAGGCCTGCCTCACCAAGCCTGCCTTCCTCGAGTTCCTCAAGCGACGGCAGGTGTGCAGCCCAGACCGTGTCACCCTCTACGGGCTGATGGTCAAGCCCATCCAGAGGTTCCCACAGTTCATACTCCTGCTTCAGGACATGCTGAAGAACACCCCCAGGGGCCATCCGGACAGGCTGTCGCTGCAGCTGGCCCTCACAGAGCTGGAGACGCTGGCTGAGAAGCTGAACGAGCAGAAGCGGCTGGCTGACCAGGTGGCTGAGATCCAGCAGCTGACCAAGAGCGTCAGTGACCGCAGCAGCCTCAACAAGCTGTTGACCTCAGGCCAGCGGCAGCTGCTCCTGTGTGAGACGTTGACGGAGACCGTGTACGGTGACCGCGGGCAGCTAATTAAGTCCAAGGAGCGTCGGGTCTTCCTGCTCAACGACATGCTTGTCTGTGCCAACATCAACTTCAAGCCTGCCAACCACAGGGGCCAGCTGGAGATCAGCAGCCTGGTGCCCCTGGGGCCCAAGTATGTGGTGAAGTGGAACACGGCGCTGCCCCAGGTGCAGGTGGTGGAGGTGGGCCAGGACGGTGGCACCTATGACAAGGACAATGTGCTCATCCAGCACTCAGGCGCCAAGAAGGCCTCTGCCTCAGGGCAGGCTCAGAATAAGGTGTACCTCGGCCCCCCACGCCTCTTCCAGGAGCTGCAGGACCTGCAGAAGGACCTGGCCGTGGTGGAGCAGATCACGCTTCTCATCAGCACGCTGCACGGCACCTACCAGAACCTGAACATGACTGTGGCTCAAGACTGGTGCCTGGCCCTGCAGAGGCTGATGCGGGTGAAGGAGGAAGAGATCCACTCGGCCAACAAGTGCCGTCTCAGGCTCCTGCTTCCTGGGAAACCCGACAAGTCCGGCCGCCCCATTAGCTTCATGGTGGTTTTCATCACCCCCAACCCCCTGAGCAAGATTTCCTGGGTCAACAGGTTACATTTGGCCAAAATCGGACTCCGGGAGGAGAACCAGCCAGGCTGGCTATGCCCGGATGAGGACAAGAAGAGCAAAGCCCCATTCTGGTGCCCGATCCTGGCCTGCTGCATCCCTGCCTTCTCCTCCCGGGCACTCAGCCTGCAGCTTGGGGCCCTGGTCCACAGTCCTGTCAACTGTCCCCTGCTGGGTTTCTCAGCAGTCAGCACCTCCCTTCCACAGGGCTACCTCTGGGTCGGGGGCGGACAGGAAGGCGCAGGGGGCCAGGTGGAAATCTTTTCCTTGAACCGGCCCTCGCCCCGCACCGTCAAGTCCTTCCCACTGGCAGCCCCTGTGCTCTGCATGGAGTATATCCCGGAGCTGGAGGAGGAGGCGGAGAGCAGAGACGAGAGCCCGACAGTTGCTGACCCCTCGGCCACGGTGCATCCAACCATCTGCCTCGGGCTCCAGGATGGCAGCATCCTCCTCTACAGCAGTGTGGACACTGGCACCCAGTGCCTGGTGAGCTGCAGGAGCCCAGGTCTGCAGCCTGTGCTCTGCCTGCGACACAGCCCCTTCCACCTGCTCGCTGGCCTGCAGGATGGGACCCTTGCTGCTTACCCTCGGACCAGCGGAGGTGTCCTGTGGGACCTGGAGAGCCCTCCCGTGTGCCTGACTGTGGGGCCCGGGCCTGTCCGCACCCTGTTGAGCCTGGAGGATGCCGTGTGGGCCAGCTGTGGGCCCTGGGTCACTGTCCTGGAAGCCACCACCCTGCAGCCTCAGCAAAGCTTCGAGGCGCACCAGGACGAGGCAGTGAGCGTGACACACATGGTGAAGGCGGGCAGCGGCGTCTGGATGGCCTTCTCCTCCGGCACCTCCATCCGCCTCTTCCACACTGAGACCCTGGAGCATCTGCAAGAGATCAACATCGCCACCAGGACCACCTTCCTCCTGCCAGGCCAGAAGCACTTGTGTGTCACCAGCCTCCTGATCTGCCAGGGTCTGCTCTGGGTGGGCACTGACCAGGGTGTCATCGTCCTGCTGCCCGTGCCTCGGCTGGAAGGCATCCCCAAGATCACAGGGAAAGGCATGGTCTCACTCAACGGGCACTGTGGGCCTGTGGCCTTCCTGGCTGTGGCTACCAGCATCCTGGCCCCTGACATCCTGCGGAGTGACCAGGAGGAGGCTGAGGGGCCCCGGGCTGAGGAGGACAAGCCAGACGGGCAGGCACACGAGCCCATGCCCGATAGCCACGTGGGCCGAGAGCTGACCCGCAAGAAGGGCATCCTCTTGCAGTACCGCCTGCGCTCCACCGCACACCTCCCGGGCCCGCTGCTCTCCATGCGGGAGCCGGCGCCTGCTGATGGCGCAGCTTTGGAGCACAGCGAGGAGGACGGCTCCATTTACGAGATGGCCGACGACCCCGACATCTGGGTGCGCAGCCGGCCCTGCGCCCGCGACGCCCACCGCAAGGAGATTTGCTCTGTGGCCATCATCTCCGGCGGGCAGGGCTACCGCAACTTTGGCAGCGCTCTGGGCAGCAGTGGGAGGCAGGCCCCGTGTGGGGAGACGGACAGCACCCTCCTCATCTGGCAGGTGCCCTTGATGCTATAG'}
+        self.ENST00000361221 = {0: 'ARHGEF10L', 1: '+', 2: 'ATGGCTTCCTCCAACCCTCCTCCACAGCCTGCCATAGGAGATCAGCTGGTTCCAGGAGTCCCAGGCCCCTCCTCTGAGGCAGAGGACGACCCAGGAGAGGCGTTTGAGTTTGATGACAGTGATGATGAAGAGGACACCAGCGCAGCCCTGGGCGTCCCCAGCCTTGCTCCTGAGAGGGACACAGACCCCCCACTGATCCACTTGGACTCCATCCCTGTCACTGACCCAGACCCAGCAGCTGCTCCACCCGGCACAGGGGTGCCAGCCTGGGTGAGCAATGGGGATGCAGCGGACGCAGCCTTCTCCGGGGCCCGGCACTCCAGCTGGAAGCGGAAGAGTTCCCGTCGCATTGACCGGTTCACTTTCCCCGCCCTGGAAGAGGATGTGATTTATGACGACGTCCCCTGCGAGAGCCCAGATGCGCATCAGCCCGGGGCAGAGAGGAACCTGCTCTACGAGGATGCGCACCGGGCTGGGGCCCCTCGGCAGGCGGAGGACCTAGGCTGGAGCTCCAGTGAGTTCGAGAGCTACAGCGAGGACTCGGGGGAGGAGGCCAAGCCGGAGGTCGAGGTCGAGCCCGCCAAGCACCGAGTGTCCTTCCAGCCCAAGCTTTCTCCAGACCTGACTAGGCTAAAGGAGAGATACGCCAGGACTAAGAGAGACATCTTGGCTTTGAGAGTTGGGGGGAGAGACATGCAGGAGCTGAAGCACAAGTACGATTGTAAGATGACCCAGCTCATGAAGGCCGCCAAGAGCGGGACCAAGGATGGGCTGGAGAAGACACGGATGGCCGTGATGCGCAAAGTCTCCTTCCTGCACAGGAAGGACGTCCTCGGTGACTCGGAGGAGGAGGACATGGGGCTCCTGGAGGTCAGCGTTTCGGACATCAAGCCCCCAGCCCCAGAGCTGGGCCCCATGCCAGAGGGCCTGAGCCCTCAGCAGGTGGTCCGGAGGCATATCCTGGGCTCCATCGTGCAGAGCGAAGGCAGCTACGTGGAGTCTCTGAAGCGGATACTCCAGGACTACCGCAACCCCCTGATGGAGATGGAGCCCAAGGCGCTGAGCGCCCGCAAGTGCCAGGTGGTGTTCTTCCGCGTGAAGGAGATCCTGCACTGCCACTCCATGTTCCAGATCGCCCTGTCCTCCCGCGTGGCTGAGTGGGATTCCACCGAGAAGATCGGGGACCTCTTCGTGGCCTCGTTTTCCAAGTCCATGGTGCTAGATGTGTACAGTGACTACGTGAACAACTTCACCAGTGCCATGTCCATCATCAAGAAGGCCTGCCTCACCAAGCCTGCCTTCCTCGAGTTCCTCAAGCGACGGCAGGTGTGCAGCCCAGACCGTGTCACCCTCTACGGGCTGATGGTCAAGCCCATCCAGAGGTTCCCACAGTTCATACTCCTGCTTCAGGACATGCTGAAGAACACCCCCAGGGGCCATCCGGACAGGCTGTCGCTGCAGCTGGCCCTCACAGAGCTGGAGACGCTGGCTGAGAAGCTGAACGAGCAGAAGCGGCTGGCTGACCAGGTGGCTGAGATCCAGCAGCTGACCAAGAGCGTCAGTGACCGCAGCAGCCTCAACAAGCTGTTGACCTCAGGCCAGCGGCAGCTGCTCCTGTGTGAGACGTTGACGGAGACCGTGTACGGTGACCGCGGGCAGCTAATTAAGTCCAAGGAGCGTCGGGTCTTCCTGCTCAACGACATGCTTGTCTGTGCCAACATCAACTTCAAGCCTGCCAACCACAGGGGCCAGCTGGAGATCAGCAGCCTGGTGCCCCTGGGGCCCAAGTATGTGGTGAAGTGGAACACGGCGCTGCCCCAGGTGCAGGTGGTGGAGGTGGGCCAGGACGGTGGCACCTATGACAAGGACAATGTGCTCATCCAGCACTCAGGCGCCAAGAAGGCCTCTGCCTCAGGGCAGGCTCAGAATAAGGTGTACCTCGGCCCCCCACGCCTCTTCCAGGAGCTGCAGGACCTGCAGAAGGACCTGGCCGTGGTGGAGCAGATCACGCTTCTCATCAGCACGCTGCACGGCACCTACCAGAACCTGAACATGACTGTGGCTCAAGACTGGTGCCTGGCCCTGCAGAGGCTGATGCGGGTGAAGGAGGAAGAGATCCACTCGGCCAACAAGTGCCGTCTCAGGCTCCTGCTTCCTGGGAAACCCGACAAGTCCGGCCGCCCCATTAGCTTCATGGTGGTTTTCATCACCCCCAACCCCCTGAGCAAGATTTCCTGGGTCAACAGGTTACATTTGGCCAAAATCGGACTCCGGGAGGAGAACCAGCCAGGCTGGCTATGCCCGGATGAGGACAAGAAGAGCAAAGCCCCATTCTGGTGCCCGATCCTGGCCTGCTGCATCCCTGCCTTCTCCTCCCGGGCACTCAGCCTGCAGCTTGGGGCCCTGGTCCACAGTCCTGTCAACTGTCCCCTGCTGGGTTTCTCAGCAGTCAGCACCTCCCTTCCACAGGGCTACCTCTGGGTCGGGGGCGGACAGGAAGGCGCAGGGGGCCAGGTGGAAATCTTTTCCTTGAACCGGCCCTCGCCCCGCACCGTCAAGTCCTTCCCACTGGCAGCCCCTGTGCTCTGCATGGAGTATATCCCGGAGCTGGAGGAGGAGGCGGAGAGCAGAGACGAGAGCCCGACAGTTGCTGACCCCTCGGCCACGGTGCATCCAACCATCTGCCTCGGGCTCCAGGATGGCAGCATCCTCCTCTACAGCAGTGTGGACACTGGCACCCAGTGCCTGGTGAGCTGCAGGAGCCCAGGTCTGCAGCCTGTGCTCTGCCTGCGACACAGCCCCTTCCACCTGCTCGCTGGCCTGCAGGATGGGACCCTTGCTGCTTACCCTCGGACCAGCGGAGGTGTCCTGTGGGACCTGGAGAGCCCTCCCGTGTGCCTGACTGTGGGGCCCGGGCCTGTCCGCACCCTGTTGAGCCTGGAGGATGCCGTGTGGGCCAGCTGTGGGCCCTGGGTCACTGTCCTGGAAGCCACCACCCTGCAGCCTCAGCAAAGCTTCGAGGCGCACCAGGACGAGGCAGTGAGCGTGACACACATGGTGAAGGCGGGCAGCGGCGTCTGGATGGCCTTCTCCTCCGGCACCTCCATCCGCCTCTTCCACACTGAGACCCTGGAGCATCTGCAAGAGATCAACATCGCCACCAGGACCACCTTCCTCCTGCCAGGCCAGAAGCACTTGTGTGTCACCAGCCTCCTGATCTGCCAGGGTCTGCTCTGGGTGGGCACTGACCAGGGTGTCATCGTCCTGCTGCCCGTGCCTCGGCTGGAAGGCATCCCCAAGATCACAGGGAAAGGCATGGTCTCACTCAACGGGCACTGTGGGCCTGTGGCCTTCCTGGCTGTGGCTACCAGCATCCTGGCCCCTGACATCCTGCGGAGTGACCAGGAGGAGGCTGAGGGGCCCCGGGCTGAGGAGGACAAGCCAGACGGGCAGGCACACGAGCCCATGCCCGATAGCCACGTGGGCCGAGAGCTGACCCGCAAGAAGGGCATCCTCTTGCAGTACCGCCTGCGCTCCACCGCACACCTCCCGGGCCCGCTGCTCTCCATGCGGGAGCCGGCGCCTGCTGATGGCGCAGCTTTGGAGCACAGCGAGGAGGACGGCTCCATTTACGAGATGGCCGACGACCCCGACATCTGGGTGCGCAGCCGGCCCTGCGCCCGCGACGCCCACCGCAAGGAGATTTGCTCTGTGGCCATCATCTCCGGCGGGCAGGGCTACCGCAACTTTGGCAGCGCTCTGGGCAGCAGTGGGAGGCAGGCCCCGTGTGGGGAGACGGACAGCACCCTCCTCATCTGGCAGGTGCCCTTGATGCTATAG'}
+        self.ENST00000361221_grch38 = {0: 'ARHGEF10L', 1: '+', 2:
+        "ATGGCTTCCTCCAACCCTCCTCCACAGCCTGCCATAGGAGATCAGCTGGTTCCAGGAGTCCCAGGCCCCTCCTCTGAGGCAGAGGACGACCCAGGAGAGGCGTTTGAGTTTGATGACAGTGATGATGAAGAGGACACCAGCGCAGCCCTGGGCGTCCCCAGCCTTGCTCCTGAGAGGGACACAGACCCCCCACTGATCCACTTGGACTCCATCCCTGTCACTGACCCAGACCCAGCAGCTGCTCCACCCGGCACAGGGGTGCCAGCCTGGGTGAGCAATGGGGATGCAGCGGACGCAGCCTTCTCCGGGGCCCGGCACTCCAGCTGGAAGCGGAAGAGTTCCCGTCGCATTGACCGGTTCACTTTCCCCGCCCTGGAAGAGGATGTGATTTATGACGACGTCCCCTGCGAGAGCCCAGATGCGCATCAGCCCGGGGCAGAGAGGAACCTGCTCTACGAGGATGCGCACCGGGCTGGGGCCCCTCGGCAGGCGGAGGACCTAGGCTGGAGCTCCAGTGAGTTCGAGAGCTACAGCGAGGACTCGGGGGAGGAGGCCAAGCCGGAGGTCGAGGTCGAGCCCGCCAAGCACCGAGTGTCCTTCCAGCCCAAGCTTTCTCCAGACCTGACTAGGCTAAAGGAGAGATACGCCAGGACTAAGAGAGACATCTTGGCTTTGAGAGTTGGGGGGAGAGACATGCAGGAGCTGAAGCACAAGTACGATTGTAAGATGACCCAGCTCATGAAGGCCGCCAAGAGCGGGACCAAGGATGGGCTGGAGAAGACACGGATGGCCGTGATGCGCAAAGTCTCCTTCCTGCACAGGAAGGACGTCCTCGGTGACTCGGAGGAGGAGGACATGGGGCTCCTGGAGGTCAGCGTTTCGGACATCAAGCCCCCAGCCCCAGAGCTGGGCCCCATGCCAGAGGGCCTGAGCCCTCAGCAGGTGGTCCGGAGGCATATCCTGGGCTCCATCGTGCAGAGCGAAGGCAGCTACGTGGAGTCTCTGAAGCGGATACTCCAGGACTACCGCAACCCCCTGATGGAGATGGAGCCCAAGGCGCTGAGCGCCCGCAAGTGCCAGGTGGTGTTCTTCCGCGTGAAGGAGATCCTGCACTGCCACTCCATGTTCCAGATCGCCCTGTCCTCCCGCGTGGCTGAGTGGGATTCCACCGAGAAGATCGGGGACCTCTTCGTGGCCTCGTTTTCCAAGTCCATGGTGCTAGATGTGTACAGTGACTACGTGAACAACTTCACCAGTGCCATGTCCATCATCAAGAAGGCCTGCCTCACCAAGCCTGCCTTCCTCGAGTTCCTCAAGCGACGGCAGGTGTGCAGCCCAGACCGTGTCACCCTCTACGGGCTGATGGTCAAGCCCATCCAGAGGTTCCCACAGTTCATACTCCTGCTTCAGGACATGCTGAAGAACACCCCCAGGGGCCATCCGGACAGGCTGTCGCTGCAGCTGGCCCTCACAGAGCTGGAGACGCTGGCTGAGAAGCTGAACGAGCAGAAGCGGCTGGCTGACCAGGTGGCTGAGATCCAGCAGCTGACCAAGAGCGTCAGTGACCGCAGCAGCCTCAACAAGCTGTTGACCTCAGGCCAGCGGCAGCTGCTCCTGTGTGAGACGTTGACGGAGACCGTGTACGGTGACCGCGGGCAGCTAATTAAGTCCAAGGAGCGTCGGGTCTTCCTGCTCAACGACATGCTTGTCTGTGCCAACATCAACTTCAAGCCTGCCAACCACAGGGGCCAGCTGGAGATCAGCAGCCTGGTGCCCCTGGGGCCCAAGTATGTGGTGAAGTGGAACACGGCGCTGCCCCAGGTGCAGGTGGTGGAGGTGGGCCAGGACGGTGGCACCTATGACAAGGACAATGTGCTCATCCAGCACTCAGGCGCCAAGAAGGCCTCTGCCTCAGGGCAGGCTCAGAATAAGGTGTACCTCGGCCCCCCACGCCTCTTCCAGGAGCTGCAGGACCTGCAGAAGGACCTGGCCGTGGTGGAGCAGATCACGCTTCTCATCAGCACGCTGCACGGCACCTACCAGAACCTGAACATGACTGTGGCTCAAGACTGGTGCCTGGCCCTGCAGAGGCTGATGCGGGTGAAGGAGGAAGAGATCCACTCGGCCAACAAGTGCCGTCTCAGGCTCCTGCTTCCTGGGAAACCCGACAAGTCCGGCCGCCCCATTAGCTTCATGGTGGTTTTCATCACCCCCAACCCCCTGAGCAAGATTTCCTGGGTCAACAGGTTACATTTGGCCAAAATCGGACTCCGGGAGGAGAACCAGCCAGGCTGGCTATGCCCGGATGAGGACAAGAAGAGCAAAGCCCCATTCTGGTGCCCGATCCTGGCCTGCTGCATCCCTGCCTTCTCCTCCCGGGCACTCAGCCTGCAGCTTGGGGCCCTGGTCCACAGTCCTGTCAACTGTCCCCTGCTGGGTTTCTCAGCAGTCAGCACCTCCCTTCCACAGGGCTACCTCTGGGTCGGGGGCGGACAGGAAGGCGCAGGGGGCCAGGTGGAAATCTTTTCCTTGAACCGGCCCTCGCCCCGCACCGTCAAGTCCTTCCCACTGGCAGCCCCTGTGCTCTGCATGGAGTATATCCCGGAGCTGGAGGAGGAGGCGGAGAGCAGAGACGAGAGCCCGACAGTTGCTGACCCCTCGGCCACGGTGCATCCAACCATCTGCCTCGGGCTCCAGGATGGCAGCATCCTCCTCTACAGCAGTGTGGACACTGGCACCCAGTGCCTGGTGAGCTGCAGGAGCCCAGGTCTGCAGCCTGTGCTCTGCCTGCGACACAGCCCCTTCCACCTGCTCGCTGGCCTGCAGGATGGGACCCTTGCTGCTTACCCTCGGACCAGCGGAGGTGTCCTGTGGGACCTGGAGAGCCCTCCCGTGTGCCTGACTGTGGGGCCCGGGCCTGTCCGCACCCTGTTGAGCCTGGAGGATGCCGTGTGGGCCAGCTGTGGGCCCCGGGTCACTGTCCTGGAAGCCACCACCCTGCAGCCTCAGCAAAGCTTCGAGGCGCACCAGGACGAGGCAGTGAGCGTGACACACATGGTGAAGGCGGGCAGCGGCGTCTGGATGGCCTTCTCCTCCGGCACCTCCATCCGCCTCTTCCACACTGAGACCCTGGAGCATCTGCAAGAGATCAACATCGCCACCAGGACCACCTTCCTCCTGCCAGGCCAGAAGCACTTGTGTGTCACCAGCCTCCTGATCTGCCAGGGTCTGCTCTGGGTGGGCACTGACCAGGGTGTCATCGTCCTGCTGCCCGTGCCTCGGCTGGAAGGCATCCCCAAGATCACAGGGAAAGGCATGGTCTCACTCAACGGGCACTGTGGGCCTGTGGCCTTCCTGGCTGTGGCTACCAGCATCCTGGCCCCTGACATCCTGCGGAGTGACCAGGAGGAGGCTGAGGGGCCCCGGGCTGAGGAGGACAAGCCAGACGGGCAGGCACACGAGCCCATGCCCGATAGCCACGTGGGCCGAGAGCTGACCCGCAAGAAGGGCATCCTCTTGCAGTACCGCCTGCGCTCCACCGCACACCTCCCGGGCCCGCTGCTCTCCATGCGGGAGCCGGCGCCTGCTGATGGCGCAGCTTTGGAGCACAGCGAGGAGGACGGCTCCATTTACGAGATGGCCGACGACCCCGACATCTGGGTGCGCAGCCGGCCCTGCGCCCGCGACGCCCACCGCAAGGAGATTTGCTCTGTGGCCATCATCTCCGGCGGGCAGGGCTACCGCAACTTTGGCAGCGCTCTGGGCAGCAGTGGGAGGCAGGCCCCGTGTGGGGAGACGGACAGCACCCTCCTCATCTGGCAGGTGCCCTTGATGCTATAG"}
+        self.ENST00000000233_5 = {0: '', 1: '+', 2: 'ATGGGCCTCACCGTGTCCGCGCTCTTTTCGCGGATCTTCGGGAAGAAGCAGATGCGGATTCTCATGGTTGGCTTGGATGCGGCTGGCAAGACCACAATCCTGTACAAACTGAAGTTGGGGGAGATTGTCACCACCATCCCAACCATAGGCTTCAATGTAGAAACAGTGGAATATAAGAACATCTGTTTCACAGTCTGGGACGTGGGAGGCCAGGACAAGATTCGGCCTCTGTGGCGGCACTACTTCCAGAACACTCAGGGCCTCATCTTTGTGGTGGACAGTAATGACCGGGAGCGGGTCCAAGAATCTGCTGATGAACTCCAGAAGATGCTGCAGGAGGACGAGCTGCGGGATGCAGTGCTGCTGGTATTTGCCAACAAGCAGGACATGCCCAACGCCATGCCCGTGAGCGAGCTGACTGACAAGCTGGGGCTACAGCACTTACGCAGCCGCACGTGGTATGTCCAGGCCACCTGTGCCACCCAAGGCACAGGTCTGTACGATGGTCTGGACTGGCTGTCCCACGAGCTGTCAAAGCGCTAA'}
         self.ENSEMBL_ensg = "ENSG00000138674"
         self.tp53_ensembl_biomart = [{0: 'ENSG00000141510', 1: '-', 3: 'ENST00000413465', 4: 'ENSP00000410739'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000359597', 4: 'ENSP00000352610'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000504290', 4: ''}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000510385', 4: ''}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000504937', 4: ''}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000269305', 4: 'ENSP00000269305'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000455263', 4: 'ENSP00000398846'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000420246', 4: 'ENSP00000391127'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000445888', 4: 'ENSP00000391478'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000576024', 4: 'ENSP00000458393'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000509690', 4: 'ENSP00000425104'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000514944', 4: 'ENSP00000423862'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000574684', 4: ''}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000505014', 4: ''}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000508793', 4: 'ENSP00000424104'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000604348', 4: 'ENSP00000473895'}, {0: 'ENSG00000141510', 1: '-', 3: 'ENST00000503591', 4: 'ENSP00000426252'}]
         self.vcf_path1 = os.path.join(os.path.dirname(inspect.getfile(epytope)), "Data/examples/vcftestfile1.vcf")  # general
         self.vcf_path2 = os.path.join(os.path.dirname(inspect.getfile(epytope)), "Data/examples/vcftestfile2.vcf")  # no annot
         self.vcf_path3 = os.path.join(os.path.dirname(inspect.getfile(epytope)), "Data/examples/vcftestfile3.vcf")  # checkallvatiationtypesindetail
+        self.expected_biomart_mart_header = ["database","default","displayName","host", "includeDatasets","martUser","name","path","port","serverVirtualSchema","visible"]
 
     def test_read_lines(self):
         alleles = FileReader.read_lines(self.ale_path, in_type=Allele)
@@ -90,21 +91,54 @@ def test_EnsemblAdapter(self):
                          self.ENSEMBL_ensg)
 
     def test_MartsAdapter(self):
-        ma = MartsAdapter(biomart="http://grch37.ensembl.org")
-
-        self.assertEqual((1515, 1529), ma.get_transcript_position('ENST00000361221', '17953929', '17953943', type=EIdentifierTypes.ENSEMBL))
-        self.assertIsNone(ma.get_transcript_position("ENST00000614237", 7566927, 7566927, type=EIdentifierTypes.ENSEMBL))
-        #logging.captureWarnings(True)
-        #result = ma.get_transcript_position("ENST00000614237", 7566927, 7566927, type=EIdentifierTypes.ENSEMBL)
-        self.assertEqual("TP53", ma.get_gene_by_position(17, 7566927, 7566927))
-        self.assertIsNone(ma.get_product_sequence("Q15942", type=EIdentifierTypes.UNIPROT))
-        self.assertEqual(self.NP_001005353, ma.get_product_sequence("NP_001005353", type=EIdentifierTypes.REFSEQ))
-        self.assertEqual(self.ENSP00000369497, ma.get_product_sequence("ENSP00000369497", type=EIdentifierTypes.ENSEMBL))
-        self.assertEqual(self.ENST00000361221[2], ma.get_transcript_sequence('ENST00000361221', type=EIdentifierTypes.ENSEMBL))
-        self.assertIsNone(ma.get_transcript_sequence("ENST00000614237", type=EIdentifierTypes.ENSEMBL))
-        self.assertDictEqual(self.ENST00000361221, ma.get_transcript_information('ENST00000361221', type=EIdentifierTypes.ENSEMBL))
-        self.assertIsNone(ma.get_transcript_information("ENST00000614237", type=EIdentifierTypes.ENSEMBL))
-        #self.assertListEqual(ma.get_ensembl_ids_from_id('TP53', type=EIdentifierTypes.GENENAME), self.tp53_ensembl_biomart)
+        # test most recent and stable GRCh37 Mart version
+        urls = ["https://www.ensembl.org", "https://grch37.ensembl.org"]
+        self.maxDiff = None
+        for url in urls:
+            ma = MartsAdapter(biomart=url)
+            if "grch37" in url:
+                self.assertEqual((1515, 1529), ma.get_transcript_position(
+                    'ENST00000361221', 17953929, 17953943, type=EIdentifierTypes.ENSEMBL))
+                self.assertEqual("TP53", ma.get_gene_by_position(17, 7566927, 7566927))
+                self.assertEqual(self.ENST00000361221[2], ma.get_transcript_sequence(
+                'ENST00000361221', type=EIdentifierTypes.ENSEMBL))
+                self.assertIsNone(ma.get_transcript_sequence(
+                "ENST00000614237", type=EIdentifierTypes.ENSEMBL))
+                self.assertEqual(self.ENST00000000233_5[2], ma.get_transcript_sequence(
+                "ENST00000000233.5", type=EIdentifierTypes.ENSEMBL))
+                self.assertDictEqual(self.ENST00000361221, ma.get_transcript_information(
+                'ENST00000361221', type=EIdentifierTypes.ENSEMBL))
+                self.assertIsNone(ma.get_transcript_information(
+                "ENST00000614237", type=EIdentifierTypes.ENSEMBL))
+                self.assertEqual(self.ENST00000361221, ma.get_transcript_information_from_protein_id('ENSP00000355060'))
+                self.assertEqual(ma.get_ensembl_ids_from_gene("TP53")[0][EAdapterFields.PROTID], ma.get_ensembl_ids_from_gene("ENSG00000141510.11", type=EIdentifierTypes.ENSEMBL)[0][EAdapterFields.PROTID])
+            else:
+                self.assertEqual((1054.0, 1054.0),ma.get_transcript_position(
+                    "ENST00000614237", 7566927, 7566927, type=EIdentifierTypes.ENSEMBL))
+                self.assertEqual("SENP3", ma.get_gene_by_position(17, 7566927, 7566927))
+                self.assertEqual(self.ENST00000361221_grch38[2], ma.get_transcript_sequence(
+                'ENST00000361221', type=EIdentifierTypes.ENSEMBL))
+                self.assertIsNotNone(ma.get_transcript_sequence(
+                "ENST00000614237", type=EIdentifierTypes.ENSEMBL))
+                self.assertDictEqual(self.ENST00000361221_grch38, ma.get_transcript_information(
+                'ENST00000361221', type=EIdentifierTypes.ENSEMBL))
+                self.assertIsNotNone(ma.get_transcript_information(
+                "ENST00000614237", type=EIdentifierTypes.ENSEMBL))
+                self.assertEqual(self.ENST00000361221_grch38, ma.get_transcript_information_from_protein_id('ENSP00000355060'))
+            self.assertIsNone(ma.get_product_sequence(
+                "Q15942", type=EIdentifierTypes.UNIPROT))
+            self.assertEqual(self.NP_001005353, ma.get_product_sequence(
+                "NP_001005353", type=EIdentifierTypes.REFSEQ))
+            self.assertEqual(self.ENSP00000369497, ma.get_product_sequence(
+                "ENSP00000369497", type=EIdentifierTypes.ENSEMBL))
+            self.assertIsNotNone(ma.get_ensembl_ids_from_gene("TP53"))
+            self.assertIsNotNone(ma.get_genes_from_location("1","100000","200000"))
+            self.assertIsNotNone(ma.get_protein_ids_from_transcripts(["ENST00000361221"]))
+            self.assertEqual(ma.get_protein_ids_from_transcripts(["ENST00000361221"])["uniprot_id"][0], "Q9HCE6")
+            self.assertIsNotNone(ma.get_variants_from_transcript_id('ENST00000361221'))
+            self.assertTrue(all(ma.get_marts().columns == self.expected_biomart_mart_header))
+            self.assertIsNotNone(ma.get_datasets("ENSEMBL_MART_ENSEMBL"))
+            self.assertEqual(ma.get_gene_names_from_ids(["ENSG00000000003"])["gene_name"][0],"TSPAN6")
 
     def test_UniProtAdapter(self):
         self.assertWarnings(DeprecationWarning, UniProtDB)