A "smart" way of obtaining liftover chain files.
    By default acts as follows:
     1. If the file ``<from_db>To<to_db>.over.chain.gz`` exists in <search_dir>,
        opens it for reading via gzip.open.
     2. Otherwise, if the file ``<from_db>To<to_db>.over.chain`` exists
        in the <search_dir> opens it (as uncompressed file).
        Steps 1 and 2 may be disabled if search_dir is set to None.
     3. Otherwise, checks whether ``<cache_dir>/<from_db>To<to_db>.over.chain.gz`` exists.
        This step may be disabled by specifying cache_dir = None.
     4. If file still not found attempts to download the file from the URL
        'http://hgdownload.cse.ucsc.edu/goldenPath/<from_db>/liftOver/<from_db>To<to_db>.over.chain.gz'
        to a temporary location. This step may be disabled by specifying use_web=False. In this case the operation fails and 
        the function returns None.
     5. At this point, if write_cache=True and cache_dir is not None and writable, the file is copied to cache_dir and opened from there.
        Otherwise it is opened from the temporary location.
        
    In case of errors (e.g. URL cannot be opened), None is returned.

def open_liftover_chain_file(from_db, to_db, search_dir='.', cache_dir=os.path.expanduser("~/.pyliftover"), use_web=True, write_cache=True):
    '''
    A "smart" way of obtaining liftover chain files.
    By default acts as follows:
     1. If the file ``<from_db>To<to_db>.over.chain.gz`` exists in <search_dir>,
        opens it for reading via gzip.open.
     2. Otherwise, if the file ``<from_db>To<to_db>.over.chain`` exists
        in the <search_dir> opens it (as uncompressed file).
        Steps 1 and 2 may be disabled if search_dir is set to None.
     3. Otherwise, checks whether ``<cache_dir>/<from_db>To<to_db>.over.chain.gz`` exists.
        This step may be disabled by specifying cache_dir = None.
     4. If file still not found attempts to download the file from the URL
        'http://hgdownload.cse.ucsc.edu/goldenPath/<from_db>/liftOver/<from_db>To<to_db>.over.chain.gz'
        to a temporary location. This step may be disabled by specifying use_web=False. In this case the operation fails and 
        the function returns None.
     5. At this point, if write_cache=True and cache_dir is not None and writable, the file is copied to cache_dir and opened from there.
        Otherwise it is opened from the temporary location.
        
    In case of errors (e.g. URL cannot be opened), None is returned.
    '''
    to_db = to_db[0].upper() + to_db[1:]
    FILE_NAME_GZ = '%sTo%s.over.chain.gz' % (from_db, to_db)
    FILE_NAME = '%sTo%s.over.chain' % (from_db, to_db)
    
    if search_dir is not None:
        FILE_GZ = os.path.join(search_dir, FILE_NAME_GZ)
        FILE = os.path.join(search_dir, FILE_NAME)
        if os.path.isfile(FILE_GZ):
            return gzip.open(FILE_GZ, 'rb')
        elif os.path.isfile(FILE):
            return open(FILE, 'rb')
    if cache_dir is not None:
        FILE_GZ = os.path.join(cache_dir, FILE_NAME_GZ)
        if os.path.isfile(FILE_GZ):
            return gzip.open(FILE_GZ, 'rb')
    if use_web:
        # Download file from the web.
        try:
            url = 'http://hgdownload.cse.ucsc.edu/goldenPath/%s/liftOver/%sTo%s.over.chain.gz' % (from_db, from_db, to_db)
            (filename, headers) = _urlopener.retrieve(url)
        except:
            # Download failed, exit
            return None
        # Move the file to cache?
        if write_cache and (cache_dir is not None):
            try:
                if not os.path.isdir(cache_dir):
                    os.mkdir(cache_dir)
                shutil.move(filename, FILE_GZ)
                # Move successful, open from cache
                return gzip.open(FILE_GZ, 'rb')
            except:
                # Move failed, open file from temp location
                return gzip.open(filename, 'rb')
        else:
            # Open from temp location
            return gzip.open(filename, 'rb')
    # If we didn't quit before this place, all failed.
    return None