<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def esearch(database, query, userhistory=True, webenv=False, query_key=False, retstart=False, retmax=False, api_key=False, email=False, **kwargs) -> Optional[EsearchResult]: """Search for a query using the Entrez ESearch API. Parameters database : str Entez database to search. query : str Query string userhistory : bool Tells API to return a WebEnV and query_key. webenv : str An Entrez WebEnv to use saved history. query_key : str An Entrez query_key to use saved history. retstart : int Return values starting at this index. retmax : int Return at most this number of values. api_key : str A users API key which allows more requests per second email : str A users email which is required if not using API. Returns ------- EsearchResult A named tuple with values [ids, count, webenv, query_key] """

    cleaned_query = urllib.parse.quote_plus(query, safe='/+')

    url = BASE_URL + f'esearch.fcgi?db={database}&term={cleaned_query}&retmode=json'
    url = check_userhistory(userhistory, url)
    url = check_webenv(webenv, url)
    url = check_query_key(query_key, url)
    url = check_retstart(retstart, url)
    url = check_retmax(retmax, url)
    url = check_api_key(api_key, url)
    url = check_email(email, url)

    time.sleep(PAUSE)
    resp = requests.get(url)
    if resp.status_code != 200:
        print('There was a server error')
        return

    text = resp.json()
    time.sleep(.5)
    return EsearchResult(
        text['esearchresult'].get('idlist', []),
        make_number(text['esearchresult'].get('count', ''), int),
        text['esearchresult'].get('webenv', ''),
        text['esearchresult'].get('querykey', '')
    )