From a1520adaa50d6697e5464fd36ffc5b1c326fbc13 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 29 Feb 2024 19:51:42 +0100 Subject: [PATCH 01/51] Updated Default cache folder --- geniml/bbclient/bbclient.py | 8 +++++--- geniml/bbclient/const.py | 10 ++++++++-- geniml/bbclient/utils.py | 20 ++++++++++++++++---- requirements/requirements-all.txt | 2 +- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/geniml/bbclient/bbclient.py b/geniml/bbclient/bbclient.py index 843ba4c1..eca4f93b 100644 --- a/geniml/bbclient/bbclient.py +++ b/geniml/bbclient/bbclient.py @@ -4,6 +4,7 @@ from logging import getLogger from typing import List, NoReturn, Union + import requests from ubiquerg import is_url @@ -21,7 +22,7 @@ DEFAULT_CACHE_FOLDER, MODULE_NAME, ) -from .utils import BedCacheManager, get_bbclient_path_folder +from .utils import BedCacheManager, get_abs_path _LOGGER = getLogger(MODULE_NAME) @@ -39,8 +40,9 @@ def __init__( if not given it will be the environment variable `BBCLIENT_CACHE` :param bedbase_api: url to bedbase """ - # get default cache folder from environment variable set by user - super().__init__(get_bbclient_path_folder(cache_folder)) + cache_folder = get_abs_path(cache_folder) + super().__init__(cache_folder) + self.bedbase_api = bedbase_api def load_bedset(self, bedset_id: str) -> BedSet: diff --git a/geniml/bbclient/const.py b/geniml/bbclient/const.py index 5074e4a3..77fbb6a4 100644 --- a/geniml/bbclient/const.py +++ b/geniml/bbclient/const.py @@ -1,12 +1,18 @@ import os +MODULE_NAME = "bbclient" + DEFAULT_BEDBASE_API = "https://api.bedbase.org" DEFAULT_BEDSET_SUBFOLDER = "bedsets" DEFAULT_BEDFILE_SUBFOLDER = "bedfiles" DEFAULT_BEDSET_EXT = ".txt" DEFAULT_BEDFILE_EXT = ".bed.gz" -DEFAULT_CACHE_FOLDER = "$BBCLIENT_CACHE" BEDSET_URL_PATTERN = "{bedbase_api}/bedset/{bedset_id}/bedfiles" BEDFILE_URL_PATTERN = "{bedbase_api}/objects/bed.{bed_id}.bedfile/access/http/bytes" -MODULE_NAME = "bbclient" + + +HOME_PATH = os.getenv("HOME") +if not HOME_PATH: + HOME_PATH = os.path.expanduser("~") +DEFAULT_CACHE_FOLDER = os.path.join(HOME_PATH, ".bbcache/") diff --git a/geniml/bbclient/utils.py b/geniml/bbclient/utils.py index 3afa2e4d..6145c042 100644 --- a/geniml/bbclient/utils.py +++ b/geniml/bbclient/utils.py @@ -2,6 +2,7 @@ import os from io import BytesIO from typing import Optional +from pathlib import Path import genomicranges import pandas as pd @@ -15,7 +16,11 @@ def __init__(self, cache_folder: str): self.create_cache_folder() def create_cache_folder(self, subfolder_path: Optional[str] = None) -> None: - """Create cache folder if it doesn't exist""" + """ + Create cache folder if it doesn't exist + + :param subfolder_path: path to the subfolder + """ if subfolder_path is None: subfolder_path = self.cache_folder @@ -62,8 +67,15 @@ def decompress_and_convert_to_genomic_ranges(content: bytes) -> genomicranges.Ge return gr -def get_bbclient_path_folder(path: str = DEFAULT_CACHE_FOLDER): +def get_abs_path(path: str = DEFAULT_CACHE_FOLDER, create_folder: bool = True) -> str: """ - Get the cache folder path either from input or environment variable '$BBCLIENT_CACHE' + Get absolute path to the folder and create it if it doesn't exist + + :param path: path to the folder + :param create_folder: create folder if it doesn't exist + + :return: absolute path to the folder """ - return os.path.expandvars(path) + absolute_cache_folder = os.path.expandvars(path) + Path(absolute_cache_folder).mkdir(parents=True, exist_ok=True) + return absolute_cache_folder diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index 7438e055..9e15589b 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -8,7 +8,7 @@ logmuse matplotlib numpy >= 1.24.0 paramiko >= 3.0.0 -peppy>=0.40.0a4 +peppy>=0.40.1 pyBigWig qdrant_client requests >= 2.31.0 From f76429e041fd23f009c7ce0639c9e8abc5a4eaf3 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 29 Feb 2024 19:51:54 +0100 Subject: [PATCH 02/51] lint --- geniml/bedspace/pipeline/bedspace_train.py | 1 - geniml/search/backends/dbbackend.py | 4 +--- geniml/search/backends/filebackend.py | 4 +--- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/geniml/bedspace/pipeline/bedspace_train.py b/geniml/bedspace/pipeline/bedspace_train.py index 1cc75605..2078cb06 100755 --- a/geniml/bedspace/pipeline/bedspace_train.py +++ b/geniml/bedspace/pipeline/bedspace_train.py @@ -2,7 +2,6 @@ bedfile embeding pipeline (train) """ - import argparse import itertools import os diff --git a/geniml/search/backends/dbbackend.py b/geniml/search/backends/dbbackend.py index 13fdc0dd..3c41a022 100644 --- a/geniml/search/backends/dbbackend.py +++ b/geniml/search/backends/dbbackend.py @@ -143,9 +143,7 @@ def __len__(self) -> int: """ return self.qd_client.get_collection(collection_name=self.collection).vectors_count - def retrieve_info( - self, ids: Union[List[int], int], with_vec: bool = False - ) -> Union[ + def retrieve_info(self, ids: Union[List[int], int], with_vec: bool = False) -> Union[ Dict[str, Union[int, List[float], Dict[str, str]]], List[Dict[str, Union[int, List[float], Dict[str, str]]]], ]: diff --git a/geniml/search/backends/filebackend.py b/geniml/search/backends/filebackend.py index e79fb8ae..16e5bcd0 100644 --- a/geniml/search/backends/filebackend.py +++ b/geniml/search/backends/filebackend.py @@ -160,9 +160,7 @@ def search( def __len__(self) -> int: return self.idx.element_count - def retrieve_info( - self, ids: Union[List[int], int], with_vec: bool = False - ) -> Union[ + def retrieve_info(self, ids: Union[List[int], int], with_vec: bool = False) -> Union[ Dict[str, Union[int, List[float], Dict[str, str]]], List[Dict[str, Union[int, List[float], Dict[str, str]]]], ]: From 3a75b3a01ef29d379f678b90d9cf924de91da72a Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 29 Feb 2024 23:18:14 +0100 Subject: [PATCH 03/51] work on reading bed files --- geniml/bbclient/bbclient.py | 11 +++---- geniml/bbclient/const.py | 3 +- geniml/bbclient/utils.py | 3 +- geniml/io/exceptions.py | 7 +++++ geniml/io/io.py | 40 ++++++++++++++++++------- tests/data/io_data/bed/s1_a_headers.bed | 7 +++++ tests/test_bbclient.py | 2 +- 7 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 tests/data/io_data/bed/s1_a_headers.bed diff --git a/geniml/bbclient/bbclient.py b/geniml/bbclient/bbclient.py index eca4f93b..9f788231 100644 --- a/geniml/bbclient/bbclient.py +++ b/geniml/bbclient/bbclient.py @@ -30,7 +30,7 @@ class BBClient(BedCacheManager): def __init__( self, - cache_folder: str = DEFAULT_CACHE_FOLDER, + cache_folder: Union[str, os.PathLike] = DEFAULT_CACHE_FOLDER, bedbase_api: str = DEFAULT_BEDBASE_API, ): """ @@ -47,9 +47,9 @@ def __init__( def load_bedset(self, bedset_id: str) -> BedSet: """ - Loads a BED set from cache, or downloads and caches it plus BED files in it if it doesn't exist + Load a BEDset from cache, or download and add it to the cache with its BED files - :param bedset_id: unique identifier of BED set + :param BedSet: BedSet object """ file_path = self._bedset_path(bedset_id) @@ -91,6 +91,7 @@ def load_bed(self, bed_id: str) -> RegionSet: Loads a BED file from cache, or downloads and caches it if it doesn't exist :param bed_id: unique identifier of a BED file + :return: the RegionSet object """ file_path = self._bedfile_path(bed_id) @@ -132,8 +133,8 @@ def add_bed_to_cache(self, bedfile: Union[RegionSet, str]) -> str: """ Add a BED file to the cache - :param bedfile: a RegionSet class or a path to a BED file to be added to cache - :return: the identifier if the BedFile object + :param bedfile: a RegionSet object or a path or url to the BED file + :return: the RegionSet identifier """ if isinstance(bedfile, str): bedfile = RegionSet(bedfile) diff --git a/geniml/bbclient/const.py b/geniml/bbclient/const.py index 77fbb6a4..cbeabf77 100644 --- a/geniml/bbclient/const.py +++ b/geniml/bbclient/const.py @@ -11,8 +11,9 @@ BEDSET_URL_PATTERN = "{bedbase_api}/bedset/{bedset_id}/bedfiles" BEDFILE_URL_PATTERN = "{bedbase_api}/objects/bed.{bed_id}.bedfile/access/http/bytes" +BBCLIENT_CACHE_ENV = "BBCLIENT_CACHE" HOME_PATH = os.getenv("HOME") if not HOME_PATH: HOME_PATH = os.path.expanduser("~") -DEFAULT_CACHE_FOLDER = os.path.join(HOME_PATH, ".bbcache/") +DEFAULT_CACHE_FOLDER = os.getenv(BBCLIENT_CACHE_ENV) or os.path.join(HOME_PATH, ".bbcache/") diff --git a/geniml/bbclient/utils.py b/geniml/bbclient/utils.py index 6145c042..037f422a 100644 --- a/geniml/bbclient/utils.py +++ b/geniml/bbclient/utils.py @@ -77,5 +77,6 @@ def get_abs_path(path: str = DEFAULT_CACHE_FOLDER, create_folder: bool = True) - :return: absolute path to the folder """ absolute_cache_folder = os.path.expandvars(path) - Path(absolute_cache_folder).mkdir(parents=True, exist_ok=True) + if create_folder: + Path(absolute_cache_folder).mkdir(parents=True, exist_ok=True) return absolute_cache_folder diff --git a/geniml/io/exceptions.py b/geniml/io/exceptions.py index 21900beb..47438224 100644 --- a/geniml/io/exceptions.py +++ b/geniml/io/exceptions.py @@ -7,3 +7,10 @@ class BackedFileNotAvailableError(GenimlBaseError): def __init__(self, message: Optional[str] = None): super().__init__(message or self.default_message) + + +class BEDFileReadError(GenimlBaseError): + default_message = "Error reading BED file." + + def __init__(self, message: Optional[str] = None): + super().__init__(message or self.default_message) diff --git a/geniml/io/io.py b/geniml/io/io.py index a05baba9..d26024cd 100644 --- a/geniml/io/io.py +++ b/geniml/io/io.py @@ -3,6 +3,7 @@ from typing import List, Union, NoReturn import pyarrow from ubiquerg import is_url +import logging import numpy as np import pandas as pd @@ -22,7 +23,9 @@ MAF_STRAND_COL_NAME, ) from .utils import extract_maf_col_positions, is_gzipped, read_bedset_file -from .exceptions import BackedFileNotAvailableError +from .exceptions import BackedFileNotAvailableError, BEDFileReadError + +_LOGGER = logging.getLogger("bbclient") class Region: @@ -51,7 +54,7 @@ def __init__(self, regions: Union[str, List[Region]], backed: bool = False): bed files. You can still iterate over the regions, but you cannot index into them. :param regions: path, or url to bed file or list of Region objects - :param backed: whether to load the bed file into memory or not + :param backed: whether to load the bed file into memory or not [Default: False] """ # load from file if isinstance(regions, str): @@ -86,13 +89,8 @@ def __init__(self, regions: Union[str, List[Region]], backed: bool = False): else: if is_gzipped(regions): df = self._read_gzipped_file(regions) - else: - # if file is gzipped, catch error and open using gzip - try: - df = pd.read_csv(regions, sep="\t", header=None, engine="pyarrow") - except pyarrow.lib.ArrowInvalid: - df = self._read_gzipped_file(regions) + df = self._read_file_pd(regions, sep="\t", header=None, engine="pyarrow") _regions = [] df.apply( @@ -114,15 +112,14 @@ def __init__(self, regions: Union[str, List[Region]], backed: bool = False): self._identifier = None - @staticmethod - def _read_gzipped_file(file_path: str) -> pd.DataFrame: + def _read_gzipped_file(self, file_path: str) -> pd.DataFrame: """ Read a gzipped file into a pandas dataframe :param file_path: path to gzipped file :return: pandas dataframe """ - return pd.read_csv( + return self._read_file_pd( file_path, sep="\t", compression="gzip", @@ -130,6 +127,27 @@ def _read_gzipped_file(file_path: str) -> pd.DataFrame: engine="pyarrow", ) + def _read_file_pd(self, *args, **kwargs) -> pd.DataFrame: + """ + Read bed file into a pandas DataFrame, and skip header rows if needed + + :return: pandas dataframe + """ + max_rows = 5 + row_count = 0 + while row_count <= max_rows: + try: + df = pd.read_csv(*args, **kwargs, skiprows=row_count) + if row_count > 0: + _LOGGER.info(f"Skipped {row_count} rows while standardization. File: '{args}'") + df = df.dropna(axis=1) + return df + except (pd.errors.ParserError, pd.errors.EmptyDataError) as _: + if row_count <= max_rows: + row_count += 1 + # if can't open file after 5 attempts try to open it with gzip + return self._read_gzipped_file(*args) + def __len__(self): return self.length diff --git a/tests/data/io_data/bed/s1_a_headers.bed b/tests/data/io_data/bed/s1_a_headers.bed new file mode 100644 index 00000000..107ad60f --- /dev/null +++ b/tests/data/io_data/bed/s1_a_headers.bed @@ -0,0 +1,7 @@ +# THIS is big header +# with 4 lines +# and 3rd line +# is empty +chr1 10 30 +chr1 110 130 +chr1 210 230 diff --git a/tests/test_bbclient.py b/tests/test_bbclient.py index 62a381f6..71c4afbb 100644 --- a/tests/test_bbclient.py +++ b/tests/test_bbclient.py @@ -58,7 +58,7 @@ def test_init_no_cache_folder(self): with pytest.raises(TypeError): BBClient(cache_folder=None) - def test_bed_caching_from_path(self, tmp_path, local_bedfile_path): + def test_bed_caching_from_path(self, local_bedfile_path, tmp_path): bbclient = BBClient(cache_folder=tmp_path) bedfile_id = bbclient.add_bed_to_cache(local_bedfile_path) assert bedfile_id is not None From 62727547d80e48f5028f2934e5c98ec02a30cad8 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 4 Mar 2024 23:31:36 +0100 Subject: [PATCH 04/51] fixed #138 --- geniml/bbclient/bbclient.py | 89 +++++++++++++++++++++++++++++- geniml/bbclient/const.py | 3 + requirements/requirements-all.txt | 2 + requirements/requirements-test.txt | 1 + tests/test_bbclient.py | 35 ++++++++++++ 5 files changed, 129 insertions(+), 1 deletion(-) diff --git a/geniml/bbclient/bbclient.py b/geniml/bbclient/bbclient.py index 9f788231..e8538634 100644 --- a/geniml/bbclient/bbclient.py +++ b/geniml/bbclient/bbclient.py @@ -3,7 +3,8 @@ import shutil from logging import getLogger from typing import List, NoReturn, Union - +import boto3 +from botocore.exceptions import ClientError import requests from ubiquerg import is_url @@ -21,6 +22,8 @@ DEFAULT_BEDSET_SUBFOLDER, DEFAULT_CACHE_FOLDER, MODULE_NAME, + DEFAULT_BUCKET_FOLDER, + DEFALUT_BUCKET_NAME, ) from .utils import BedCacheManager, get_abs_path @@ -166,12 +169,96 @@ def add_bed_to_cache(self, bedfile: Union[RegionSet, str]) -> str: return bedfile_id + def add_bed_to_s3( + self, + identifier: str, + bucket: str = DEFALUT_BUCKET_NAME, + endpoint_url: str = None, + aws_access_key_id: str = None, + aws_secret_access_key: str = None, + s3_path: str = DEFALUT_BUCKET_FOLDER, + ) -> str: + """ + Add a cached BED file to S3 + + :param identifier: the unique identifier of the BED file + :param bucket: the name of the bucket + :param endpoint_url: the URL of the S3 endpoint [Default: set up by the environment vars] + :param aws_access_key_id: the access key of the AWS account [Default: set up by the environment vars] + :param aws_secret_access_key: the secret access key of the AWS account [Default: set up by the environment vars] + :param s3_path: the path on S3 + + :return: full path on S3 + """ + s3_client = boto3.client( + "s3", + endpoint_url=endpoint_url, + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + ) + local_file_path = self.seek(identifier) + bed_file_name = os.path.basename(local_file_path) + s3_bed_path = os.path.join(identifier[0], identifier[1], bed_file_name) + if s3_path: + s3_bed_path = os.path.join(s3_path, s3_bed_path) + + s3_client.upload_file(local_file_path, bucket, s3_bed_path) + _LOGGER.info(f"Project was uploaded successfully to s3://{bucket}/{s3_bed_path}") + return s3_bed_path + + def get_bed_from_s3( + self, + identifier: str, + bucket: str = DEFALUT_BUCKET_NAME, + endpoint_url: str = None, + aws_access_key_id: str = None, + aws_secret_access_key: str = None, + s3_path: str = DEFAULT_BUCKET_FOLDER, + ) -> str: + """ + Get a cached BED file from S3 and cache it locally + + :param identifier: the unique identifier of the BED file + :param bucket: the name of the bucket + :param endpoint_url: the URL of the S3 endpoint [Default: set up by the environment vars] + :param aws_access_key_id: the access key of the AWS account [Default: set up by the environment vars] + :param aws_secret_access_key: the secret access key of the AWS account [Default: set up by the environment vars] + :param s3_path: the path on S3 + + :return: bed file id + :raise FileNotFoundError: if the identifier does not exist in cache + """ + s3_bed_path = os.path.join( + identifier[0], identifier[1], f"{identifier}{DEFAULT_BEDFILE_EXT}" + ) + if s3_path: + s3_bed_path = os.path.join(s3_path, s3_bed_path) + + s3_client = boto3.client( + "s3", + endpoint_url=endpoint_url, + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + ) + try: + s3_client.download_file( + bucket, s3_bed_path, self._bedfile_path(identifier, create=True) + ) + except ClientError as e: + if e.response["Error"]["Code"] == "404": + raise FileNotFoundError(f"{identifier} does not exist in S3.") + else: + raise e + + return identifier + def seek(self, identifier: str) -> str: """ Get local path to BED file or BED set with specific identifier :param identifier: the unique identifier :return: the local path of the file + :raise FileNotFoundError: if the identifier does not exist in cache """ # check if any BED set has that identifier diff --git a/geniml/bbclient/const.py b/geniml/bbclient/const.py index cbeabf77..c3006992 100644 --- a/geniml/bbclient/const.py +++ b/geniml/bbclient/const.py @@ -17,3 +17,6 @@ if not HOME_PATH: HOME_PATH = os.path.expanduser("~") DEFAULT_CACHE_FOLDER = os.getenv(BBCLIENT_CACHE_ENV) or os.path.join(HOME_PATH, ".bbcache/") + +DEFALUT_BUCKET_NAME = "bedbase" +DEFAULT_BUCKET_FOLDER = "bed_files" diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index 9e15589b..24956075 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -19,3 +19,5 @@ ubiquerg >= 0.6.3 pyarrow iranges lightning +botocore >= 1.34.54 +boto3 >= 1.34.54 \ No newline at end of file diff --git a/requirements/requirements-test.txt b/requirements/requirements-test.txt index 3e466db5..4ca61516 100644 --- a/requirements/requirements-test.txt +++ b/requirements/requirements-test.txt @@ -1,2 +1,3 @@ pytest pytest-remotedata +pytest-mock \ No newline at end of file diff --git a/tests/test_bbclient.py b/tests/test_bbclient.py index 71c4afbb..110f92c3 100644 --- a/tests/test_bbclient.py +++ b/tests/test_bbclient.py @@ -2,9 +2,13 @@ import genomicranges import pytest +from unittest.mock import Mock from geniml.bbclient import BBClient from geniml.io import BedSet, RegionSet +import boto3 +import botocore + DATA_TEST_FOLDER = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "tests", @@ -140,3 +144,34 @@ def test_bedbase_caching(tmp_path, bedset_id, bedfile_id, request): # check the path and identifier of BED file bedfile_path = bbclient.seek(bedfile_id) assert bedfile.compute_bed_identifier() == os.path.split(bedfile_path)[1].split(".")[0] + + +def test_upload_s3(mocker, local_bedfile_path, tmp_path): + bbclient = BBClient(cache_folder=tmp_path) + bedfile_id = bbclient.add_bed_to_cache(local_bedfile_path) + upload_mock = mocker.patch( + "boto3.s3.inject.upload_file", + ) + bbclient.add_bed_to_s3(bedfile_id, s3_path="test_test") + assert upload_mock.called + + +def test_download_s3(mocker, local_bedfile_path, tmp_path): + bbclient = BBClient(cache_folder=tmp_path) + download_mock = mocker.patch( + "boto3.s3.inject.download_file", + ) + bbclient.get_bed_from_s3("test_id", s3_path="test_test") + assert download_mock.called + + +def test_download_s3_404(mocker, local_bedfile_path, tmp_path): + bbclient = BBClient(cache_folder=tmp_path) + download_mock = mocker.patch( + "boto3.s3.inject.download_file", + side_effect=botocore.exceptions.ClientError({"Error": {"Code": "404"}}, "operation_name"), + ) + with pytest.raises(FileNotFoundError): + bbclient.get_bed_from_s3("test_id", s3_path="test_test") + + assert download_mock.called From 7f0a5ce066e7d7f77b0f2b78c085e86bef49a2dc Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 4 Mar 2024 23:50:25 +0100 Subject: [PATCH 05/51] fixed spelling error --- geniml/bbclient/bbclient.py | 2 +- tests/test_bbclient.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/geniml/bbclient/bbclient.py b/geniml/bbclient/bbclient.py index e8538634..0c1fc516 100644 --- a/geniml/bbclient/bbclient.py +++ b/geniml/bbclient/bbclient.py @@ -176,7 +176,7 @@ def add_bed_to_s3( endpoint_url: str = None, aws_access_key_id: str = None, aws_secret_access_key: str = None, - s3_path: str = DEFALUT_BUCKET_FOLDER, + s3_path: str = DEFAULT_BUCKET_FOLDER, ) -> str: """ Add a cached BED file to S3 diff --git a/tests/test_bbclient.py b/tests/test_bbclient.py index 110f92c3..0af93d00 100644 --- a/tests/test_bbclient.py +++ b/tests/test_bbclient.py @@ -67,6 +67,7 @@ def test_bed_caching_from_path(self, local_bedfile_path, tmp_path): bedfile_id = bbclient.add_bed_to_cache(local_bedfile_path) assert bedfile_id is not None + @pytest.mark.parametrize("bedfile_path", local_bedfile_path()) def test_bed_caching_from_region_set(self, tmp_path, local_bedfile_path): bbclient = BBClient(cache_folder=tmp_path) bedfile = RegionSet(local_bedfile_path) From 68ad32b1bc3c63277c296a1fdd585ef978b8b2da Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 5 Mar 2024 00:36:53 +0100 Subject: [PATCH 06/51] updated and fixed tests --- geniml/io/io.py | 16 +++++++- tests/test_bbclient.py | 85 +++++++++++++++++++++++------------------- 2 files changed, 61 insertions(+), 40 deletions(-) diff --git a/geniml/io/io.py b/geniml/io/io.py index d26024cd..1042035e 100644 --- a/geniml/io/io.py +++ b/geniml/io/io.py @@ -177,8 +177,22 @@ def __iter__(self): mode = "r" with open_func(self.path, mode) as f: + skipped_lines = 0 + max_skipped_lines = 5 for line in f: - chr, start, stop = line.split("\t")[:3] + + try: + chr, start, stop = line.split("\t")[:3] + except ValueError as _: + if skipped_lines < max_skipped_lines: + skipped_lines += 1 + continue + else: + raise BEDFileReadError(f"Could not read line bed file") + if skipped_lines > 0: + _LOGGER.info( + f"Skipped {skipped_lines} lines while opening file. File: '{self.path}'" + ) yield Region(chr, int(start), int(stop)) else: for region in self.regions: diff --git a/tests/test_bbclient.py b/tests/test_bbclient.py index 0af93d00..6f733cd9 100644 --- a/tests/test_bbclient.py +++ b/tests/test_bbclient.py @@ -47,13 +47,17 @@ def local_bedfile_list(): return ALL_BEDFILE_PATH +class TestBedCaching: + pass + + class TestBBClientCaching: def test_init(self, cache_path): """ Test initialization of BBClient """ bbclient = BBClient(cache_folder=cache_path) - assert bbclient is not None + assert isinstance(bbclient, BBClient) def test_init_no_cache_folder(self): """ @@ -62,15 +66,16 @@ def test_init_no_cache_folder(self): with pytest.raises(TypeError): BBClient(cache_folder=None) - def test_bed_caching_from_path(self, local_bedfile_path, tmp_path): + @pytest.mark.parametrize("bedfile_path", ALL_BEDFILE_PATH) + def test_bed_caching_from_path(self, bedfile_path, tmp_path): bbclient = BBClient(cache_folder=tmp_path) - bedfile_id = bbclient.add_bed_to_cache(local_bedfile_path) + bedfile_id = bbclient.add_bed_to_cache(bedfile_path) assert bedfile_id is not None - @pytest.mark.parametrize("bedfile_path", local_bedfile_path()) - def test_bed_caching_from_region_set(self, tmp_path, local_bedfile_path): + @pytest.mark.parametrize("bedfile_path", ALL_BEDFILE_PATH) + def test_bed_caching_from_region_set(self, tmp_path, bedfile_path): bbclient = BBClient(cache_folder=tmp_path) - bedfile = RegionSet(local_bedfile_path) + bedfile = RegionSet(bedfile_path) bbclient.add_bed_to_cache(bedfile) path_in_cache = bbclient.seek(bedfile.identifier) assert bedfile.compute_bed_identifier() == os.path.split(path_in_cache)[1].split(".")[0] @@ -82,14 +87,14 @@ def test_bedset_caching(self, tmp_path, local_bedfile_list): path_in_cache = bbclient.seek(bedset_id) assert bedset_id == os.path.split(path_in_cache)[1].split(".")[0] - def test_error_bed_not_in_cache(self, tmp_path, local_bedfile_path): + def test_bed_not_in_cache_error(self, tmp_path, local_bedfile_path): bbclient = BBClient(cache_folder=tmp_path) # skip caching bedfile = RegionSet(local_bedfile_path) with pytest.raises(FileNotFoundError): bbclient.seek(bedfile.identifier) - def test_error_bedset_not_in_cache(self, tmp_path, local_bedfile_list): + def test_bedset_not_in_cache_error(self, tmp_path, local_bedfile_list): bbclient = BBClient(cache_folder=tmp_path) bedset_id = BedSet(local_bedfile_list).identifier with pytest.raises(FileNotFoundError): @@ -113,6 +118,39 @@ def test_remove_bedset_from_cache(self, tmp_path, local_bedfile_list): bbclient.seek(bedset_id) +class TestS3Caching: + def test_upload_s3(self, mocker, local_bedfile_path, tmp_path): + bbclient = BBClient(cache_folder=tmp_path) + bedfile_id = bbclient.add_bed_to_cache(local_bedfile_path) + upload_mock = mocker.patch( + "boto3.s3.inject.upload_file", + ) + bbclient.add_bed_to_s3(bedfile_id, s3_path="test_test") + assert upload_mock.called + + def test_download_s3(self, mocker, local_bedfile_path, tmp_path): + bbclient = BBClient(cache_folder=tmp_path) + download_mock = mocker.patch( + "boto3.s3.inject.download_file", + ) + bbclient.get_bed_from_s3("test_id", s3_path="test_test") + assert download_mock.called + + def test_download_s3_404(self, mocker, local_bedfile_path, tmp_path): + bbclient = BBClient(cache_folder=tmp_path) + download_mock = mocker.patch( + "boto3.s3.inject.download_file", + side_effect=botocore.exceptions.ClientError( + {"Error": {"Code": "404"}}, "operation_name" + ), + ) + with pytest.raises(FileNotFoundError): + bbclient.get_bed_from_s3("test_id", s3_path="test_test") + + assert download_mock.called + + +# TODO: rewrite it so that it mokes the requests # @pytest.mark.bedbase @pytest.mark.skipif( "not config.getoption('--bedbase')", @@ -145,34 +183,3 @@ def test_bedbase_caching(tmp_path, bedset_id, bedfile_id, request): # check the path and identifier of BED file bedfile_path = bbclient.seek(bedfile_id) assert bedfile.compute_bed_identifier() == os.path.split(bedfile_path)[1].split(".")[0] - - -def test_upload_s3(mocker, local_bedfile_path, tmp_path): - bbclient = BBClient(cache_folder=tmp_path) - bedfile_id = bbclient.add_bed_to_cache(local_bedfile_path) - upload_mock = mocker.patch( - "boto3.s3.inject.upload_file", - ) - bbclient.add_bed_to_s3(bedfile_id, s3_path="test_test") - assert upload_mock.called - - -def test_download_s3(mocker, local_bedfile_path, tmp_path): - bbclient = BBClient(cache_folder=tmp_path) - download_mock = mocker.patch( - "boto3.s3.inject.download_file", - ) - bbclient.get_bed_from_s3("test_id", s3_path="test_test") - assert download_mock.called - - -def test_download_s3_404(mocker, local_bedfile_path, tmp_path): - bbclient = BBClient(cache_folder=tmp_path) - download_mock = mocker.patch( - "boto3.s3.inject.download_file", - side_effect=botocore.exceptions.ClientError({"Error": {"Code": "404"}}, "operation_name"), - ) - with pytest.raises(FileNotFoundError): - bbclient.get_bed_from_s3("test_id", s3_path="test_test") - - assert download_mock.called From 075b846c828cc0d331bc19302c8e5ff35b6e7c1b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 17 Mar 2024 18:41:48 -0400 Subject: [PATCH 07/51] update on HNSWBackend --- geniml/search/backends/filebackend.py | 35 ++++--- tests/test_search.py | 129 +++++++++++++++++--------- 2 files changed, 110 insertions(+), 54 deletions(-) diff --git a/geniml/search/backends/filebackend.py b/geniml/search/backends/filebackend.py index 16e5bcd0..3041b0ce 100644 --- a/geniml/search/backends/filebackend.py +++ b/geniml/search/backends/filebackend.py @@ -1,3 +1,4 @@ +import os.path from typing import Dict, List, Tuple, Union from ... import _LOGGER @@ -28,14 +29,12 @@ class HNSWBackend(EmSearchBackend): class HNSWBackend(EmSearchBackend): """A search backend that uses a local HNSW index to store and search embeddings""" - # the index - idx: hnswlib.Index - payloads: dict # in the format of {: }, equivalent to payloads in Qdrant - idx_path: str # local path where the index is saved to + # instance variables, should not be class variables def __init__( self, local_index_path: str = DEFAULT_INDEX_PATH, + payloads: Dict = {}, space: str = DEFAULT_HNSW_SPACE, dim: int = DEFAULT_DIM, ef: int = DEFAULT_EF, @@ -51,14 +50,25 @@ def __init__( :param m: connected with internal dimensionality of the data, higher M -> higher accuracy/run_time when ef is fixed """ - + # super(HNSWBackend, self).__init__() # initiate the index self.idx = hnswlib.Index(space=space, dim=dim) # possible options are l2, cosine or ip self.idx.init_index(max_elements=0, ef_construction=ef, M=m) + # load from local index that alrady store vectors + if os.path.exists(local_index_path): + self.idx.load_index(local_index_path) + _LOGGER.info( + f"Using index {local_index_path} with {self.idx.element_count} points." + ) + self.payloads = payloads + # self.payloads = {} # save the index to local file path - self.idx.save_index(local_index_path) - self.payloads = {} + else: + _LOGGER.info(f"Index {local_index_path} does not exist, creating it.") + self.idx.save_index(local_index_path) + self.payloads = {} + # self.payloads = payloads self.idx_path = local_index_path def load( @@ -108,7 +118,8 @@ def search( offset: int = 0, ) -> Union[ List[Dict[str, Union[int, float, Dict[str, str], List[float]]]], - List[List[Dict[str, Union[int, float, Dict[str, str], List[float]]]]], + # List[List[Dict[str, Union[int, float, Dict[str, str], List[float]]]]], + List[List[Dict[str, Union[int, float, Dict[str, str], np.ndarray]]]], ]: """ With query vector(s), get the limit nearest neighbors. @@ -142,7 +153,7 @@ def search( result_id = ids[i] result_distances = distances[i] if with_vectors: - result_vectors = self.idx.get_items(result_id) + result_vectors = self.idx.get_items(result_id, return_type="numpy") for j in range(limit): output_dict = {"id": result_id[j], "distance": result_distances[j]} if with_payload: @@ -160,7 +171,9 @@ def search( def __len__(self) -> int: return self.idx.element_count - def retrieve_info(self, ids: Union[List[int], int], with_vec: bool = False) -> Union[ + def retrieve_info( + self, ids: Union[List[int], int], with_vec: bool = False + ) -> Union[ Dict[str, Union[int, List[float], Dict[str, str]]], List[Dict[str, Union[int, List[float], Dict[str, str]]]], ]: @@ -179,7 +192,7 @@ def retrieve_info(self, ids: Union[List[int], int], with_vec: bool = False) -> U output_list.append(output_dict) if with_vec: - vecs = self.idx.get_items(ids) + vecs = self.idx.get_items(ids, return_type="numpy") for i in range(len(vecs)): output_list[i]["vector"] = vecs[i] diff --git a/tests/test_search.py b/tests/test_search.py index 9f2d2619..dc11eb02 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -1,4 +1,3 @@ -import collections import os import random from typing import Dict, List @@ -79,6 +78,25 @@ def ids(filenames): return random.sample(range(len(filenames)), 5) +# @pytest.fixture +@pytest.fixture(scope="module") +def temp_data_dir(tmp_path_factory): + # temporal index folder + return tmp_path_factory.mktemp("data") + + +@pytest.fixture(scope="module") +def temp_idx_path(temp_data_dir): + # temporal index path + return temp_data_dir / "testing_idx.bin" + + +@pytest.fixture(scope="module") +def hnswb(temp_idx_path): + # init backend + return HNSWBackend(local_index_path=str(temp_idx_path)) + + @pytest.mark.skipif( "not config.getoption('--qdrant')", reason="Only run when --qdrant is given", @@ -101,7 +119,7 @@ def test_QdrantBackend(filenames, embeddings, labels, collection, ids): assert isinstance(result, dict) assert isinstance(result["id"], int) assert isinstance(result["score"], float) - assert isinstance(result["vector"], list) + assert isinstance(result["vector"], np.ndarray) for i in result["vector"]: assert isinstance(i, float) assert isinstance(result["payload"], dict) @@ -124,46 +142,15 @@ def test_QdrantBackend(filenames, embeddings, labels, collection, ids): qd_search_backend.qd_client.delete_collection(qd_search_backend.collection) -# https://github.com/pyjanitor-devs/pyjanitor/issues/115 @pytest.mark.skipif( DEP_HNSWLIB == False, reason="This test require installation of hnswlib (optional)" ) -def test_HNSWBackend(filenames, embeddings, labels, tmp_path_factory, ids): - def test_hnsw_search_result( - dict_list: List[Dict], backend: HNSWBackend, with_dist: bool = False - ): - """ - repeated test of the output of search / retrieve_info function of HNSWBackend - - :param dict_list: the result, which is supposed to be a list of dictionary - :param index: the hnswlib.Index of the backend - :param with_dist: whether distance score is included in the result - :return: - """ - index = backend.idx - assert isinstance(dict_list, list) - for result in dict_list: - assert isinstance(result, dict) - assert isinstance(result["id"], int) - if with_dist: - assert isinstance(result["distance"], float) - assert isinstance(result["payload"], dict) - assert isinstance(result["vector"], list) - assert result["vector"] == index.get_items([result["id"]])[0] - for num in result["vector"]: - assert isinstance(num, float) - - # temporal index file - temp_data_dir = tmp_path_factory.mktemp("data") - temp_idx_path = temp_data_dir / "testing_idx.bin" - # init backend - hnswb = HNSWBackend(local_index_path=str(temp_idx_path)) +def test_HNSWBackend_load(filenames, embeddings, labels, hnswb, ids): num_upload = len(filenames) # batches to load labels_1 = labels[: num_upload // 2] labels_2 = labels[num_upload // 2 :] - embeddings_1 = embeddings[: num_upload // 2] embeddings_2 = embeddings[num_upload // 2 :] @@ -174,7 +161,41 @@ def test_hnsw_search_result( # load second batch hnswb.load(embeddings_2, payloads=labels_2) assert len(hnswb) == num_upload + # pytestconfig.cache.set('shared_backend', hnswb) + +@pytest.mark.skipif( + DEP_HNSWLIB == False, reason="This test require installation of hnswlib (optional)" +) +# @pytest.mark.dependency(depends=["test_HNSWBackend_load"]) +def test_HNSWBackend_search(filenames, hnswb, ids): + def search_result_check(dict_list: List[Dict], backend: HNSWBackend, with_dist: bool = False): + """ + repeated test of the output of search / retrieve_info function of HNSWBackend to check if the result matches the content in index + + :param dict_list: the result, which is supposed to be a list of dictionary + :param backend: the HNSWBackend to be tested + :param with_dist: whether distance score is included in the result + :return: + """ + index = backend.idx + assert isinstance(dict_list, list) + for result in dict_list: + assert isinstance(result, dict) + assert isinstance(result["id"], int) + if with_dist: + assert isinstance(result["distance"], float) + assert isinstance(result["payload"], dict) + assert isinstance(result["vector"], np.ndarray) + # assert result["vector"] == index.get_items([result["id"]])[0] + assert ( + result["vector"] == index.get_items([result["id"]], return_type="numpy")[0] + ).all() + for num in result["vector"]: + assert isinstance(num, np.float32) + + # hnswb = pytestconfig.cache.get('shared_backend', None) + assert len(hnswb) == len(filenames) # test searching with one vector (np.ndarray with shape (dim,)) query_vec = np.random.random( 100, @@ -182,29 +203,51 @@ def test_hnsw_search_result( single_vec_search = hnswb.search( query_vec, 3, - # with_payload=False, - # with_vectors=False, ) single_vec_search_offset = hnswb.search( query_vec, 3, - # with_payload=False, - # with_vectors=False, offset=2, ) - assert single_vec_search_offset == single_vec_search - test_hnsw_search_result(single_vec_search, hnswb, True) - test_hnsw_search_result(single_vec_search_offset, hnswb, True) + for j in range(len(single_vec_search)): + assert single_vec_search_offset[j]["id"] == single_vec_search[j]["id"] + assert single_vec_search_offset[j]["distance"] == single_vec_search[j]["distance"] + assert ( + single_vec_search_offset[j]["payload"]["metadata"] + == single_vec_search[j]["payload"]["metadata"] + ) + search_result_check(single_vec_search, hnswb, True) + search_result_check(single_vec_search_offset, hnswb, True) # test searching with multiple vectors (np.ndarray with shape (n, dim)) multiple_vecs_search = hnswb.search(np.random.random((7, 100)), 5) assert isinstance(multiple_vecs_search, list) assert len(multiple_vecs_search) == 7 for i in range(len(multiple_vecs_search)): - test_hnsw_search_result(multiple_vecs_search[i], hnswb, True) + search_result_check(multiple_vecs_search[i], hnswb, True) # test information retrieval / get items retrieval_results = hnswb.retrieve_info(ids, True) - test_hnsw_search_result(retrieval_results, hnswb, False) + search_result_check(retrieval_results, hnswb, False) + + +@pytest.mark.skipif( + DEP_HNSWLIB == False, reason="This test require installation of hnswlib (optional)" +) +# @pytest.mark.dependency(depends=["test_HNSWBackend_load"]) +def test_HNSWBackend_save(filenames, hnswb, embeddings, temp_idx_path, temp_data_dir): + # test saving from local + new_hnswb = HNSWBackend(local_index_path=str(temp_idx_path), payloads=hnswb.payloads) + assert new_hnswb.idx.max_elements == embeddings.shape[0] + + for i in range(embeddings.shape[0]): + old_result = hnswb.idx.get_items([i], return_type="numpy") + new_result = new_hnswb.idx.get_items([i], return_type="numpy") + assert (old_result == new_result).all() + + # test a bug: + new_idx_path = temp_data_dir / "new_idx.bin" + empty_hnswb = HNSWBackend(local_index_path=str(new_idx_path)) + assert len(empty_hnswb.payloads) == 0 From 9ee54ebc9098af2e32e3b0d9486723cd10aab454 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 18 Mar 2024 16:51:14 +0100 Subject: [PATCH 08/51] Updated regions annotation --- geniml/region2vec/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/geniml/region2vec/main.py b/geniml/region2vec/main.py index aa368f5a..5e82b5f9 100644 --- a/geniml/region2vec/main.py +++ b/geniml/region2vec/main.py @@ -299,13 +299,13 @@ def export( ) def encode( - self, regions: Union[Region, List[Region]], pooling: POOLING_TYPES = None + self, regions: Union[Region, List[Region], RegionSet], pooling: POOLING_TYPES = None ) -> np.ndarray: """ Get the vector for a region. - :param Region region: Region to get the vector for. - :param str pooling: Pooling type to use. + :param regions: Region to get the vector for. + :param pooling: Pooling type to use. :return np.ndarray: Vector for the region. """ From d59feda9c83a52d37ac04cc664767ebc5f7455e2 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 20 Mar 2024 13:42:26 -0400 Subject: [PATCH 09/51] add tools to merge HNSWBackend --- geniml/search/backends/filebackend.py | 2 +- geniml/search/filebackend_tools.py | 34 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 geniml/search/filebackend_tools.py diff --git a/geniml/search/backends/filebackend.py b/geniml/search/backends/filebackend.py index 3041b0ce..c486137e 100644 --- a/geniml/search/backends/filebackend.py +++ b/geniml/search/backends/filebackend.py @@ -1,5 +1,5 @@ import os.path -from typing import Dict, List, Tuple, Union +from typing import Dict, List, Union from ... import _LOGGER diff --git a/geniml/search/filebackend_tools.py b/geniml/search/filebackend_tools.py new file mode 100644 index 00000000..737ba829 --- /dev/null +++ b/geniml/search/filebackend_tools.py @@ -0,0 +1,34 @@ +import logging +from typing import List + +import numpy as np + +from ..const import * +from .backends.filebackend import HNSWBackend + +_LOGGER = logging.getLogger(PKG_NAME) + + +def merge_backends( + backends_to_merge: List[HNSWBackend], local_index_path: str, dim: int +) -> HNSWBackend: + """ + merge multiple backends into one + """ + + result_backend = HNSWBackend( + local_index_path=local_index_path, + payloads={}, + dim=dim, + ) + + for backend in backends_to_merge: + result_vecs = [] + result_payloads = [] + for j in range(len(backend)): + result_vecs.append(backend.idx.get_items([j], return_type="numpy")[0]) + result_payloads.append(backend.payloads[j]) + + result_backend.load(vectors=np.array(result_vecs), payloads=result_payloads) + + return result_backend From 7be185e37b73d32d7bb009af488b56590d0917d3 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 22 Mar 2024 14:01:33 +0100 Subject: [PATCH 10/51] Updated md5sum bedset --- geniml/io/io.py | 7 ++----- geniml/io/utils.py | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/geniml/io/io.py b/geniml/io/io.py index 1042035e..aad4da87 100644 --- a/geniml/io/io.py +++ b/geniml/io/io.py @@ -1,7 +1,6 @@ import gzip import os from typing import List, Union, NoReturn -import pyarrow from ubiquerg import is_url import logging @@ -22,7 +21,7 @@ MAF_START_COL_NAME, MAF_STRAND_COL_NAME, ) -from .utils import extract_maf_col_positions, is_gzipped, read_bedset_file +from .utils import extract_maf_col_positions, is_gzipped, read_bedset_file, compute_md5sum_bedset from .exceptions import BackedFileNotAvailableError, BEDFileReadError _LOGGER = logging.getLogger("bbclient") @@ -353,9 +352,7 @@ def compute_bedset_identifier(self) -> str: bedfile_ids = [] for bedfile in self.region_sets: bedfile_ids.append(bedfile.compute_bed_identifier()) - self._bedset_identifier = md5( - ";".join(sorted(bedfile_ids)).encode("utf-8") - ).hexdigest() + self._bedset_identifier = compute_md5sum_bedset(bedfile_ids) return self._bedset_identifier diff --git a/geniml/io/utils.py b/geniml/io/utils.py index c2a80b6a..4e802811 100644 --- a/geniml/io/utils.py +++ b/geniml/io/utils.py @@ -1,6 +1,8 @@ import gzip import os from typing import Dict, List, Union +from hashlib import md5 + from .const import ( MAF_CHROMOSOME_COL_NAME, @@ -70,10 +72,27 @@ def get_index_from_header(header: List[str], col_name: str) -> Union[int, None]: def read_bedset_file(file_path: str) -> List[str]: - """Load a bedset from a text file""" + """ + Load a bedset from a text file + + :param file_path: path to the file + + :return: list of bed identifiers + """ bed_identifiers = [] with open(file_path, "r") as f: for line in f: bed_identifiers.append(line.strip()) return bed_identifiers + + +def compute_md5sum_bedset(bedset: List[str]) -> str: + """ + Compute the md5sum of a bedset + + :param bedset: list of bed identifiers + + :return: md5sum of the bedset + """ + return md5("".join(bedset).encode()).hexdigest() From 68bd66aae365d2fadca2ab872c10c7bee1cf3ec8 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 22 Mar 2024 14:03:17 +0100 Subject: [PATCH 11/51] updated version --- geniml/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geniml/_version.py b/geniml/_version.py index d3ec452c..3ced3581 100644 --- a/geniml/_version.py +++ b/geniml/_version.py @@ -1 +1 @@ -__version__ = "0.2.0" +__version__ = "0.2.1" From cc3d89c88e41e6c0a54d309e88ebbc4ac250b478 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 22 Mar 2024 16:00:36 +0100 Subject: [PATCH 12/51] Fixedd #142 --- geniml/text2bednn/text2bednn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geniml/text2bednn/text2bednn.py b/geniml/text2bednn/text2bednn.py index 3332080a..2c192a79 100644 --- a/geniml/text2bednn/text2bednn.py +++ b/geniml/text2bednn/text2bednn.py @@ -467,7 +467,7 @@ def nl_vec_search( with_payload: bool = True, with_vectors: bool = False, **kwargs, - ) -> List[Dict[str, Union[int, float, Dict[str, str], List[float]]]]: + ) -> List[Dict[str, Union[int, str, float, Dict[str, str], List[float]]]]: """ Given an input natural language, suggest region sets From c8061fe071ce44dd8066cd32d589406ecd528657 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 22 Mar 2024 16:01:44 +0100 Subject: [PATCH 13/51] Updated parameters --- geniml/text2bednn/text2bednn.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/geniml/text2bednn/text2bednn.py b/geniml/text2bednn/text2bednn.py index 2c192a79..66c964e0 100644 --- a/geniml/text2bednn/text2bednn.py +++ b/geniml/text2bednn/text2bednn.py @@ -463,10 +463,9 @@ def nl_vec_search( self, query: Union[str, np.ndarray], limit: int = 10, - # offset: int = 0, + offset: int = 0, with_payload: bool = True, with_vectors: bool = False, - **kwargs, ) -> List[Dict[str, Union[int, str, float, Dict[str, str], List[float]]]]: """ Given an input natural language, suggest region sets @@ -497,8 +496,7 @@ def nl_vec_search( limit, with_payload=with_payload, with_vectors=with_vectors, - # offset=offset) - **kwargs, + offset=offset, ) def __repr__(self): From f91ad6f7354524bff12757a2744261fc3e6c6742 Mon Sep 17 00:00:00 2001 From: Julia820 Date: Mon, 25 Mar 2024 21:58:05 +0100 Subject: [PATCH 14/51] consensus new example data --- geniml/assess/assess.py | 2 +- tests/consensus/cli_test.sh | 69 -------------------------- tests/consensus/coverage/all_core.bw | Bin 125119 -> 0 bytes tests/consensus/coverage/all_end.bw | Bin 121653 -> 0 bytes tests/consensus/coverage/all_start.bw | Bin 124106 -> 0 bytes tests/consensus/raw/test_3.bed | 1 - 6 files changed, 1 insertion(+), 71 deletions(-) delete mode 100644 tests/consensus/cli_test.sh delete mode 100644 tests/consensus/coverage/all_core.bw delete mode 100644 tests/consensus/coverage/all_end.bw delete mode 100644 tests/consensus/coverage/all_start.bw diff --git a/geniml/assess/assess.py b/geniml/assess/assess.py index 9126a762..5ea0578e 100644 --- a/geniml/assess/assess.py +++ b/geniml/assess/assess.py @@ -204,7 +204,7 @@ def get_rbs_from_assessment_file(file, cs_each_file=False, flexible=False): else: df["f_t_u"] = df["median_dist_file_to_universe"] df["u_t_f"] = df["median_dist_universe_to_file"] - df["RBS"] = get_rbs(df["f_t_u"], df["u_t_t"]) + df["RBS"] = get_rbs(df["f_t_u"], df["u_t_f"]) if cs_each_file: return df else: diff --git a/tests/consensus/cli_test.sh b/tests/consensus/cli_test.sh deleted file mode 100644 index 6bc2b559..00000000 --- a/tests/consensus/cli_test.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -rm -r tests/consesnus/results -mkdir tests/consesnus/results - -# make lh model -geniml lh build_model --model-file tests/consesnus/results/lh_model.tar \ - --file-no 4 \ - --coverage-folder tests/consesnus/coverage/ - -mkdir tests/consesnus/results/universe/ -# make cut-off universe -geniml universe cc --coverage-folder tests/consesnus/coverage/ \ - --output-file tests/consesnus/results/universe/cc_universe.bed - -geniml universe ccf --coverage-folder tests/consesnus/coverage/ \ - --output-file tests/consesnus/results/universe/ccf_universe.bed - -geniml universe ml --model-file tests/consesnus/results/lh_model.tar \ - --output-file tests/consesnus/results/universe/ml_universe.bed\ - --coverage-folder tests/consesnus/coverage/ - -# make HMM universe -geniml universe hmm --output-file tests/consesnus/results/universe/hmm_universe.bed --coverage-folder tests/consesnus/coverage/ - - -# assessment - geniml assess --raw-data-folder tests/consesnus/raw/\ - --file-list tests/consesnus/file_list.txt \ - --universe tests/consesnus/results/universe/cc_universe.bed\ - --save-to-file --folder-out tests/consesnus/results/ \ - --pref cc --no-workers 1 \ - --overlap \ - --distance \ - --distance-universe-to-file - - geniml assess --raw-data-folder tests/consesnus/raw/\ - --file-list tests/consesnus/file_list.txt \ - --universe tests/consesnus/results/universe/ccf_universe.bed \ - --save-to-file --folder-out tests/consesnus/results/ \ - --pref ccf --no-workers 1 \ - --overlap \ - --distance \ - --distance-universe-to-file\ - --distance-flexible\ - --distance-flexible-universe-to-file - - geniml assess --raw-data-folder tests/consesnus/raw/\ - --file-list tests/consesnus/file_list.txt \ - --universe tests/consesnus/results/universe/ml_universe.bed \ - --save-to-file --folder-out tests/consesnus/results/ \ - --pref ml --no-workers 1 \ - --overlap \ - --distance \ - --distance-universe-to-file\ - --distance-flexible\ - --distance-flexible-universe-to-file - - geniml assess --raw-data-folder tests/consesnus/raw/\ - --file-list tests/consesnus/file_list.txt \ - --universe tests/consesnus/results/universe/hmm_universe.bed \ - --save-to-file --folder-out tests/consesnus/results/ \ - --pref hmm --no-workers 1 \ - --overlap \ - --distance \ - --distance-universe-to-file\ - --distance-flexible\ - --distance-flexible-universe-to-file - diff --git a/tests/consensus/coverage/all_core.bw b/tests/consensus/coverage/all_core.bw deleted file mode 100644 index 9174ee59b5d170426c0395ce195693d025503fac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125119 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 J(UI&sH)O}^;<{EGq`%i7; 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