Compare commits
12 Commits
2822a483e3
...
0.13.0
Author | SHA1 | Date | |
---|---|---|---|
2ea2f63f29 | |||
17932ecd71 | |||
6cdc4ff4ae | |||
4b34036d17 | |||
27ae89fde7 | |||
06dbb56c28 | |||
79fcce8b84 | |||
f4064f087e | |||
276665f5fd | |||
fd536862e2 | |||
576dc303f4 | |||
62ce1c9b2f |
25
.vscode/launch.json
vendored
25
.vscode/launch.json
vendored
@@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "autobigs info -lschema pubmlst_bordetella_seqdef",
|
|
||||||
"type": "debugpy",
|
|
||||||
"request": "launch",
|
|
||||||
"program": "${workspaceFolder}/src/autobigs/cli/program.py",
|
|
||||||
"console": "integratedTerminal",
|
|
||||||
"args": [
|
|
||||||
"info",
|
|
||||||
"-lschemas",
|
|
||||||
"pubmlst_bordetella_seqdef"
|
|
||||||
],
|
|
||||||
"cwd": "${workspaceFolder}/src",
|
|
||||||
"env": {
|
|
||||||
"PYTHONPATH": "${workspaceFolder}/src"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
10
Jenkinsfile
vendored
10
Jenkinsfile
vendored
@@ -2,8 +2,8 @@ pipeline {
|
|||||||
agent {
|
agent {
|
||||||
kubernetes {
|
kubernetes {
|
||||||
cloud 'rsys-devel'
|
cloud 'rsys-devel'
|
||||||
defaultContainer 'pip'
|
defaultContainer 'miniforge3'
|
||||||
inheritFrom 'pip'
|
inheritFrom 'miniforge'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
@@ -35,12 +35,16 @@ pipeline {
|
|||||||
stage("publish") {
|
stage("publish") {
|
||||||
parallel {
|
parallel {
|
||||||
stage ("git.reslate.systems") {
|
stage ("git.reslate.systems") {
|
||||||
|
when {
|
||||||
|
branch '**/main'
|
||||||
|
}
|
||||||
|
|
||||||
environment {
|
environment {
|
||||||
CREDS = credentials('username-password-rs-git')
|
CREDS = credentials('username-password-rs-git')
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
sh 'python -m twine upload --repository-url https://git.reslate.systems/api/packages/ydeng/pypi -u ${CREDS_USR} -p ${CREDS_PSW} --non-interactive --disable-progress-bar --verbose dist/*'
|
sh 'python -m twine upload --repository-url https://git.reslate.systems/api/packages/ydeng/pypi -u ${CREDS_USR} -p ${CREDS_PSW} --non-interactive --disable-progress-bar --verbose dist/*'
|
||||||
sh 'curl --user ${CREDS_USR}:${CRED_PSW} --upload-file conda-bld/**/*.conda https://git.reslate.systems/api/packages/${CRED_USR}/conda/$(basename conda-bld/**/*.conda)'
|
sh 'curl --user ${CREDS_USR}:${CREDS_PSW} --upload-file conda-bld/**/*.conda https://git.reslate.systems/api/packages/${CREDS_USR}/conda/$(basename conda-bld/**/*.conda)'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage ("pypi.org") {
|
stage ("pypi.org") {
|
||||||
|
19
README.md
19
README.md
@@ -1,13 +1,14 @@
|
|||||||
# autoBIGS.Engine
|
# autoBIGS.engine
|
||||||
|
|
||||||
A python library implementing common BIGSdb MLST schemes and databases accesses for the purpose of typing sequences automatically. Implementation follows the RESTful API outlined by the official [BIGSdb documentation](https://bigsdb.readthedocs.io/en/latest/rest.html) up to `V1.50.0`.
|
A python library implementing common BIGSdb MLST schemes and databases accesses for the purpose of typing sequences automatically. Implementation follows the RESTful API outlined by the official [BIGSdb documentation](https://bigsdb.readthedocs.io/en/latest/rest.html) up to `V1.50.0`.
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Briefly, this library can:
|
Briefly, this library can:
|
||||||
- Import multiple `FASTA` files
|
- Import multiple `FASTA` files
|
||||||
- Fetch the available BIGSdb databases that is currently live and available
|
- Fetch the available BIGSdb databases that is currently live and available
|
||||||
- Fetch the available BIGSdb database schemas for a given MLST database
|
- Fetch the available BIGSdb database schemes for a given MLST database
|
||||||
- Retrieve exact/non-exact MLST allele variant IDs based off a sequence
|
- Retrieve exact/non-exact MLST allele variant IDs based off a sequence
|
||||||
- Retrieve MLST sequence type IDs based off a sequence
|
- Retrieve MLST sequence type IDs based off a sequence
|
||||||
- Output all results to a single CSV
|
- Output all results to a single CSV
|
||||||
@@ -22,4 +23,16 @@ Then, it's as easy as running `pip install autobigs-engine` in any terminal that
|
|||||||
|
|
||||||
### CLI usage
|
### CLI usage
|
||||||
|
|
||||||
This is a independent python library and thus does not have any form of direct user interface. One way of using it could be to create your own Python script that makes calls to this libraries functions. Alternatively, you may use `autobigs-cli`, a `Python` package that implements a CLI for calling this library.
|
This is a independent python library and thus does not have any form of direct user interface. One way of using it could be to create your own Python script that makes calls to this libraries functions. Alternatively, you may use `autobigs-cli`, a `Python` package that implements a CLI for calling this library.
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
the autoBIGS project follows [semantic versioning](https://semver.org/) where the three numbers may be interpreted as MAJOR.MINOR.PATCH.
|
||||||
|
|
||||||
|
Note regarding major version 0 ([spec item 4](https://semver.org/#spec-item-4)), the following adaptation of semantic versioning definition is as follows:
|
||||||
|
|
||||||
|
1. Given x.Y.z, Y is only incremented when a backwards incompatible change is made.
|
||||||
|
|
||||||
|
2. Given x.y.Z, Z is only incremented when a backwards compatible change is made.
|
||||||
|
|
||||||
|
Versions of autoBIGS items with a major version number of 0 will introduce numerous changes and patches. As such, changes between such versions should be considered highly variable.
|
@@ -9,7 +9,8 @@ dependencies:
|
|||||||
- pytest-asyncio
|
- pytest-asyncio
|
||||||
- python-build
|
- python-build
|
||||||
- conda-build
|
- conda-build
|
||||||
- twine
|
- twine==6.0.1
|
||||||
- setuptools_scm
|
- setuptools_scm
|
||||||
- pytest-cov
|
- pytest-cov
|
||||||
- grayskull
|
- grayskull
|
||||||
|
- curl
|
@@ -7,7 +7,7 @@ from os import path
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Any, AsyncGenerator, AsyncIterable, Iterable, Mapping, Sequence, Set, Union
|
from typing import Any, AsyncGenerator, AsyncIterable, Coroutine, Iterable, Mapping, Sequence, Set, Union
|
||||||
|
|
||||||
from aiohttp import ClientSession, ClientTimeout
|
from aiohttp import ClientSession, ClientTimeout
|
||||||
|
|
||||||
@@ -43,10 +43,10 @@ class BIGSdbMLSTProfiler(AbstractAsyncContextManager):
|
|||||||
|
|
||||||
class RemoteBIGSdbMLSTProfiler(BIGSdbMLSTProfiler):
|
class RemoteBIGSdbMLSTProfiler(BIGSdbMLSTProfiler):
|
||||||
|
|
||||||
def __init__(self, database_api: str, database_name: str, schema_id: int):
|
def __init__(self, database_api: str, database_name: str, scheme_id: int):
|
||||||
self._database_name = database_name
|
self._database_name = database_name
|
||||||
self._schema_id = schema_id
|
self._scheme_id = scheme_id
|
||||||
self._base_url = f"{database_api}/db/{self._database_name}/schemes/{self._schema_id}/"
|
self._base_url = f"{database_api}/db/{self._database_name}/schemes/{self._scheme_id}/"
|
||||||
self._http_client = ClientSession(self._base_url, timeout=ClientTimeout(60))
|
self._http_client = ClientSession(self._base_url, timeout=ClientTimeout(60))
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
@@ -90,7 +90,7 @@ class RemoteBIGSdbMLSTProfiler(BIGSdbMLSTProfiler):
|
|||||||
)
|
)
|
||||||
yield result_allele if isinstance(sequence_string, str) else (sequence_string.name, result_allele)
|
yield result_allele if isinstance(sequence_string, str) else (sequence_string.name, result_allele)
|
||||||
else:
|
else:
|
||||||
raise NoBIGSdbMatchesException(self._database_name, self._schema_id, sequence_string.name if isinstance(sequence_string, NamedString) else None)
|
raise NoBIGSdbMatchesException(self._database_name, self._scheme_id, sequence_string.name if isinstance(sequence_string, NamedString) else None)
|
||||||
|
|
||||||
async def determine_mlst_st(self, alleles: Union[AsyncIterable[Union[Allele, tuple[str, Allele]]], Iterable[Union[Allele, tuple[str, Allele]]]]) -> Union[MLSTProfile, NamedMLSTProfile]:
|
async def determine_mlst_st(self, alleles: Union[AsyncIterable[Union[Allele, tuple[str, Allele]]], Iterable[Union[Allele, tuple[str, Allele]]]]) -> Union[MLSTProfile, NamedMLSTProfile]:
|
||||||
uri_path = "designations"
|
uri_path = "designations"
|
||||||
@@ -117,17 +117,17 @@ class RemoteBIGSdbMLSTProfiler(BIGSdbMLSTProfiler):
|
|||||||
response_json: dict = await response.json()
|
response_json: dict = await response.json()
|
||||||
allele_set: Set[Allele] = set()
|
allele_set: Set[Allele] = set()
|
||||||
response_json.setdefault("fields", dict())
|
response_json.setdefault("fields", dict())
|
||||||
schema_fields_returned: dict[str, str] = response_json["fields"]
|
scheme_fields_returned: dict[str, str] = response_json["fields"]
|
||||||
schema_fields_returned.setdefault("ST", "unknown")
|
scheme_fields_returned.setdefault("ST", "unknown")
|
||||||
schema_fields_returned.setdefault("clonal_complex", "unknown")
|
scheme_fields_returned.setdefault("clonal_complex", "unknown")
|
||||||
schema_exact_matches: dict = response_json["exact_matches"]
|
scheme_exact_matches: dict = response_json["exact_matches"]
|
||||||
for exact_match_locus, exact_match_alleles in schema_exact_matches.items():
|
for exact_match_locus, exact_match_alleles in scheme_exact_matches.items():
|
||||||
allele_set.add(Allele(exact_match_locus, exact_match_alleles[0]["allele_id"], None))
|
allele_set.add(Allele(exact_match_locus, exact_match_alleles[0]["allele_id"], None))
|
||||||
if len(allele_set) == 0:
|
if len(allele_set) == 0:
|
||||||
raise ValueError("Passed in no alleles.")
|
raise ValueError("Passed in no alleles.")
|
||||||
result_mlst_profile = MLSTProfile(allele_set, schema_fields_returned["ST"], schema_fields_returned["clonal_complex"])
|
result_mlst_profile = MLSTProfile(allele_set, scheme_fields_returned["ST"], scheme_fields_returned["clonal_complex"])
|
||||||
if len(names_list) > 0:
|
if len(names_list) > 0:
|
||||||
result_mlst_profile = NamedMLSTProfile(str(tuple(names_list)), result_mlst_profile)
|
result_mlst_profile = NamedMLSTProfile(str(tuple(names_list)) if len(set(names_list)) > 1 else names_list[0], result_mlst_profile)
|
||||||
return result_mlst_profile
|
return result_mlst_profile
|
||||||
|
|
||||||
async def profile_string(self, query_sequence_strings: Iterable[Union[NamedString, str]]) -> Union[NamedMLSTProfile, MLSTProfile]:
|
async def profile_string(self, query_sequence_strings: Iterable[Union[NamedString, str]]) -> Union[NamedMLSTProfile, MLSTProfile]:
|
||||||
@@ -135,20 +135,24 @@ class RemoteBIGSdbMLSTProfiler(BIGSdbMLSTProfiler):
|
|||||||
return await self.determine_mlst_st(alleles)
|
return await self.determine_mlst_st(alleles)
|
||||||
|
|
||||||
async def profile_multiple_strings(self, query_named_string_groups: AsyncIterable[Iterable[NamedString]], stop_on_fail: bool = False) -> AsyncGenerator[NamedMLSTProfile, Any]:
|
async def profile_multiple_strings(self, query_named_string_groups: AsyncIterable[Iterable[NamedString]], stop_on_fail: bool = False) -> AsyncGenerator[NamedMLSTProfile, Any]:
|
||||||
tasks = []
|
tasks: list[Coroutine[Any, Any, Union[NamedMLSTProfile, MLSTProfile]]] = []
|
||||||
async for named_strings in query_named_string_groups:
|
async for named_strings in query_named_string_groups:
|
||||||
tasks.append(self.profile_string(named_strings))
|
tasks.append(self.profile_string(named_strings))
|
||||||
for task in asyncio.as_completed(tasks):
|
for task in asyncio.as_completed(tasks):
|
||||||
try:
|
named_mlst_profile = await task
|
||||||
yield await task
|
try:
|
||||||
except NoBIGSdbMatchesException as e:
|
if isinstance(named_mlst_profile, NamedMLSTProfile):
|
||||||
if stop_on_fail:
|
yield named_mlst_profile
|
||||||
raise e
|
else:
|
||||||
causal_name = e.get_causal_query_name()
|
raise TypeError("MLST profile is not named.")
|
||||||
if causal_name is None:
|
except NoBIGSdbMatchesException as e:
|
||||||
raise ValueError("Missing query name despite requiring names.")
|
if stop_on_fail:
|
||||||
else:
|
raise e
|
||||||
yield NamedMLSTProfile(causal_name, None)
|
causal_name = e.get_causal_query_name()
|
||||||
|
if causal_name is None:
|
||||||
|
raise ValueError("Missing query name despite requiring names.")
|
||||||
|
else:
|
||||||
|
yield NamedMLSTProfile(causal_name, None)
|
||||||
|
|
||||||
async def close(self):
|
async def close(self):
|
||||||
await self._http_client.close()
|
await self._http_client.close()
|
||||||
@@ -165,7 +169,7 @@ class BIGSdbIndex(AbstractAsyncContextManager):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._http_client = ClientSession()
|
self._http_client = ClientSession()
|
||||||
self._known_seqdef_dbs_origin: Union[Mapping[str, str], None] = None
|
self._known_seqdef_dbs_origin: Union[Mapping[str, str], None] = None
|
||||||
self._seqdefdb_schemas: dict[str, Union[Mapping[str, int], None]] = dict()
|
self._seqdefdb_schemes: dict[str, Union[Mapping[str, int], None]] = dict()
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
@@ -191,22 +195,22 @@ class BIGSdbIndex(AbstractAsyncContextManager):
|
|||||||
raise NoSuchBIGSdbDatabaseException(seqdef_db_name)
|
raise NoSuchBIGSdbDatabaseException(seqdef_db_name)
|
||||||
return known_databases[seqdef_db_name]
|
return known_databases[seqdef_db_name]
|
||||||
|
|
||||||
async def get_schemas_for_seqdefdb(self, seqdef_db_name: str, force: bool = False) -> Mapping[str, int]:
|
async def get_schemes_for_seqdefdb(self, seqdef_db_name: str, force: bool = False) -> Mapping[str, int]:
|
||||||
if seqdef_db_name in self._seqdefdb_schemas and not force:
|
if seqdef_db_name in self._seqdefdb_schemes and not force:
|
||||||
return self._seqdefdb_schemas[seqdef_db_name] # type: ignore since it's guaranteed to not be none by conditional
|
return self._seqdefdb_schemes[seqdef_db_name] # type: ignore since it's guaranteed to not be none by conditional
|
||||||
uri_path = f"{await self.get_bigsdb_api_from_seqdefdb(seqdef_db_name)}/db/{seqdef_db_name}/schemes"
|
uri_path = f"{await self.get_bigsdb_api_from_seqdefdb(seqdef_db_name)}/db/{seqdef_db_name}/schemes"
|
||||||
async with self._http_client.get(uri_path) as response:
|
async with self._http_client.get(uri_path) as response:
|
||||||
response_json = await response.json()
|
response_json = await response.json()
|
||||||
schema_descriptions: Mapping[str, int] = dict()
|
scheme_descriptions: Mapping[str, int] = dict()
|
||||||
for scheme_definition in response_json["schemes"]:
|
for scheme_definition in response_json["schemes"]:
|
||||||
scheme_id: int = int(str(scheme_definition["scheme"]).split("/")[-1])
|
scheme_id: int = int(str(scheme_definition["scheme"]).split("/")[-1])
|
||||||
scheme_desc: str = scheme_definition["description"]
|
scheme_desc: str = scheme_definition["description"]
|
||||||
schema_descriptions[scheme_desc] = scheme_id
|
scheme_descriptions[scheme_desc] = scheme_id
|
||||||
self._seqdefdb_schemas[seqdef_db_name] = schema_descriptions
|
self._seqdefdb_schemes[seqdef_db_name] = scheme_descriptions
|
||||||
return self._seqdefdb_schemas[seqdef_db_name] # type: ignore
|
return self._seqdefdb_schemes[seqdef_db_name] # type: ignore
|
||||||
|
|
||||||
async def build_profiler_from_seqdefdb(self, local: bool, dbseqdef_name: str, schema_id: int) -> BIGSdbMLSTProfiler:
|
async def build_profiler_from_seqdefdb(self, local: bool, dbseqdef_name: str, scheme_id: int) -> BIGSdbMLSTProfiler:
|
||||||
return get_BIGSdb_MLST_profiler(local, await self.get_bigsdb_api_from_seqdefdb(dbseqdef_name), dbseqdef_name, schema_id)
|
return get_BIGSdb_MLST_profiler(local, await self.get_bigsdb_api_from_seqdefdb(dbseqdef_name), dbseqdef_name, scheme_id)
|
||||||
|
|
||||||
async def close(self):
|
async def close(self):
|
||||||
await self._http_client.close()
|
await self._http_client.close()
|
||||||
@@ -214,7 +218,7 @@ class BIGSdbIndex(AbstractAsyncContextManager):
|
|||||||
async def __aexit__(self, exc_type, exc_value, traceback):
|
async def __aexit__(self, exc_type, exc_value, traceback):
|
||||||
await self.close()
|
await self.close()
|
||||||
|
|
||||||
def get_BIGSdb_MLST_profiler(local: bool, database_api: str, database_name: str, schema_id: int):
|
def get_BIGSdb_MLST_profiler(local: bool, database_api: str, database_name: str, scheme_id: int):
|
||||||
if local:
|
if local:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
return RemoteBIGSdbMLSTProfiler(database_api=database_api, database_name=database_name, schema_id=schema_id)
|
return RemoteBIGSdbMLSTProfiler(database_api=database_api, database_name=database_name, scheme_id=scheme_id)
|
@@ -5,21 +5,21 @@ class BIGSDbDatabaseAPIException(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class NoBIGSdbMatchesException(BIGSDbDatabaseAPIException):
|
class NoBIGSdbMatchesException(BIGSDbDatabaseAPIException):
|
||||||
def __init__(self, database_name: str, database_schema_id: int, query_name: Union[None, str], *args):
|
def __init__(self, database_name: str, database_scheme_id: int, query_name: Union[None, str], *args):
|
||||||
self._query_name = query_name
|
self._query_name = query_name
|
||||||
super().__init__(f"No matches found with schema with ID {database_schema_id} in the database \"{database_name}\".", *args)
|
super().__init__(f"No matches found with scheme with ID {database_scheme_id} in the database \"{database_name}\".", *args)
|
||||||
|
|
||||||
def get_causal_query_name(self) -> Union[str, None]:
|
def get_causal_query_name(self) -> Union[str, None]:
|
||||||
return self._query_name
|
return self._query_name
|
||||||
|
|
||||||
class NoBIGSdbExactMatchesException(NoBIGSdbMatchesException):
|
class NoBIGSdbExactMatchesException(NoBIGSdbMatchesException):
|
||||||
def __init__(self, database_name: str, database_schema_id: int, *args):
|
def __init__(self, database_name: str, database_scheme_id: int, *args):
|
||||||
super().__init__(f"No exact match found with schema with ID {database_schema_id} in the database \"{database_name}\".", *args)
|
super().__init__(f"No exact match found with scheme with ID {database_scheme_id} in the database \"{database_name}\".", *args)
|
||||||
|
|
||||||
class NoSuchBIGSdbDatabaseException(BIGSDbDatabaseAPIException):
|
class NoSuchBIGSdbDatabaseException(BIGSDbDatabaseAPIException):
|
||||||
def __init__(self, database_name: str, *args):
|
def __init__(self, database_name: str, *args):
|
||||||
super().__init__(f"No database \"{database_name}\" found.", *args)
|
super().__init__(f"No database \"{database_name}\" found.", *args)
|
||||||
|
|
||||||
class NoSuchBigSdbSchemaException(BIGSDbDatabaseAPIException):
|
class NoSuchBigSdbschemeException(BIGSDbDatabaseAPIException):
|
||||||
def __init__(self, database_name: str, database_schema_id: int, *args):
|
def __init__(self, database_name: str, database_scheme_id: int, *args):
|
||||||
super().__init__(f"No schema with ID {database_schema_id} in \"{database_name}\" found.", *args)
|
super().__init__(f"No scheme with ID {database_scheme_id} in \"{database_name}\" found.", *args)
|
||||||
|
@@ -25,7 +25,7 @@ class SangerTraceData(NamedString):
|
|||||||
analysis_proto_settings_name: str
|
analysis_proto_settings_name: str
|
||||||
analysis_rpto_settings_ver: str
|
analysis_rpto_settings_ver: str
|
||||||
analysis_proto_xml_data: str
|
analysis_proto_xml_data: str
|
||||||
analysis_proto_xml_schema_ver: str
|
analysis_proto_xml_scheme_ver: str
|
||||||
sample_comment: Union[None, str]
|
sample_comment: Union[None, str]
|
||||||
capillary_machine: bool
|
capillary_machine: bool
|
||||||
container_identifier: str
|
container_identifier: str
|
||||||
|
@@ -71,14 +71,14 @@ hinfluenzae_2014_102_bad_profile = MLSTProfile((
|
|||||||
), "unknown", "unknown")
|
), "unknown", "unknown")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("local_db,database_api,database_name,schema_id,seq_path,feature_seqs_path,expected_profile,bad_profile", [
|
@pytest.mark.parametrize("local_db,database_api,database_name,scheme_id,seq_path,feature_seqs_path,expected_profile,bad_profile", [
|
||||||
(False, "https://bigsdb.pasteur.fr/api", "pubmlst_bordetella_seqdef", 3, "tohama_I_bpertussis.fasta", "tohama_I_bpertussis_features.fasta", bpertussis_tohamaI_profile, bpertussis_tohamaI_bad_profile),
|
(False, "https://bigsdb.pasteur.fr/api", "pubmlst_bordetella_seqdef", 3, "tohama_I_bpertussis.fasta", "tohama_I_bpertussis_features.fasta", bpertussis_tohamaI_profile, bpertussis_tohamaI_bad_profile),
|
||||||
(False, "https://rest.pubmlst.org", "pubmlst_hinfluenzae_seqdef", 1, "2014-102_hinfluenza.fasta", "2014-102_hinfluenza_features.fasta", hinfluenzae_2014_102_profile, hinfluenzae_2014_102_bad_profile),
|
(False, "https://rest.pubmlst.org", "pubmlst_hinfluenzae_seqdef", 1, "2014-102_hinfluenza.fasta", "2014-102_hinfluenza_features.fasta", hinfluenzae_2014_102_profile, hinfluenzae_2014_102_bad_profile),
|
||||||
])
|
])
|
||||||
class TestBIGSdbMLSTProfiler:
|
class TestBIGSdbMLSTProfiler:
|
||||||
async def test_profiling_results_in_exact_matches_when_exact(self, local_db, database_api, database_name, schema_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
async def test_profiling_results_in_exact_matches_when_exact(self, local_db, database_api, database_name, scheme_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
||||||
sequence = get_first_sequence_from_fasta(seq_path)
|
sequence = get_first_sequence_from_fasta(seq_path)
|
||||||
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, schema_id) as dummy_profiler:
|
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, scheme_id) as dummy_profiler:
|
||||||
expected_alleles = mlst.alleles_to_mapping(expected_profile.alleles)
|
expected_alleles = mlst.alleles_to_mapping(expected_profile.alleles)
|
||||||
targets_left = set(mlst.alleles_to_mapping(expected_profile.alleles).keys())
|
targets_left = set(mlst.alleles_to_mapping(expected_profile.alleles).keys())
|
||||||
async for exact_match in dummy_profiler.determine_mlst_allele_variants(query_sequence_strings=[sequence]):
|
async for exact_match in dummy_profiler.determine_mlst_allele_variants(query_sequence_strings=[sequence]):
|
||||||
@@ -89,10 +89,10 @@ class TestBIGSdbMLSTProfiler:
|
|||||||
|
|
||||||
assert len(targets_left) == 0
|
assert len(targets_left) == 0
|
||||||
|
|
||||||
async def test_sequence_profiling_non_exact_returns_non_exact(self, local_db, database_api, database_name, schema_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
async def test_sequence_profiling_non_exact_returns_non_exact(self, local_db, database_api, database_name, scheme_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
||||||
target_sequences = get_multiple_sequences_from_fasta(feature_seqs_path)
|
target_sequences = get_multiple_sequences_from_fasta(feature_seqs_path)
|
||||||
mlst_targets = {x.lower() for x in mlst.alleles_to_mapping(expected_profile.alleles).keys()}
|
mlst_targets = {x.lower() for x in mlst.alleles_to_mapping(expected_profile.alleles).keys()}
|
||||||
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, schema_id) as profiler:
|
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, scheme_id) as profiler:
|
||||||
for target_sequence in target_sequences:
|
for target_sequence in target_sequences:
|
||||||
match = re.fullmatch(r".*\[gene=([\w\d]+)\].*", target_sequence.description)
|
match = re.fullmatch(r".*\[gene=([\w\d]+)\].*", target_sequence.description)
|
||||||
if match is None:
|
if match is None:
|
||||||
@@ -102,31 +102,33 @@ class TestBIGSdbMLSTProfiler:
|
|||||||
continue
|
continue
|
||||||
scrambled = gene_scrambler(str(target_sequence.seq), 0.125)
|
scrambled = gene_scrambler(str(target_sequence.seq), 0.125)
|
||||||
async for partial_match in profiler.determine_mlst_allele_variants([scrambled]):
|
async for partial_match in profiler.determine_mlst_allele_variants([scrambled]):
|
||||||
|
assert isinstance(partial_match, Allele)
|
||||||
assert partial_match.partial_match_profile is not None
|
assert partial_match.partial_match_profile is not None
|
||||||
mlst_targets.remove(gene)
|
mlst_targets.remove(gene)
|
||||||
|
|
||||||
assert len(mlst_targets) == 0
|
assert len(mlst_targets) == 0
|
||||||
|
|
||||||
async def test_profiling_results_in_correct_mlst_st(self, local_db, database_api, database_name, schema_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
async def test_profiling_results_in_correct_mlst_st(self, local_db, database_api, database_name, scheme_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
||||||
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, schema_id) as dummy_profiler:
|
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, scheme_id) as dummy_profiler:
|
||||||
mlst_st_data = await dummy_profiler.determine_mlst_st(expected_profile.alleles)
|
mlst_st_data = await dummy_profiler.determine_mlst_st(expected_profile.alleles)
|
||||||
assert mlst_st_data is not None
|
assert mlst_st_data is not None
|
||||||
assert isinstance(mlst_st_data, MLSTProfile)
|
assert isinstance(mlst_st_data, MLSTProfile)
|
||||||
assert mlst_st_data.clonal_complex == expected_profile.clonal_complex
|
assert mlst_st_data.clonal_complex == expected_profile.clonal_complex
|
||||||
assert mlst_st_data.sequence_type == expected_profile.sequence_type
|
assert mlst_st_data.sequence_type == expected_profile.sequence_type
|
||||||
|
|
||||||
async def test_profiling_non_exact_results_in_list_of_mlsts(self, local_db, database_api, database_name, schema_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
async def test_profiling_non_exact_results_in_list_of_mlsts(self, local_db, database_api, database_name, scheme_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
||||||
dummy_alleles = bad_profile.alleles
|
dummy_alleles = bad_profile.alleles
|
||||||
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, schema_id) as dummy_profiler:
|
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, scheme_id) as dummy_profiler:
|
||||||
mlst_profile = await dummy_profiler.determine_mlst_st(dummy_alleles)
|
mlst_profile = await dummy_profiler.determine_mlst_st(dummy_alleles)
|
||||||
|
assert isinstance(mlst_profile, MLSTProfile)
|
||||||
assert mlst_profile.clonal_complex == "unknown"
|
assert mlst_profile.clonal_complex == "unknown"
|
||||||
assert mlst_profile.sequence_type == "unknown"
|
assert mlst_profile.sequence_type == "unknown"
|
||||||
|
|
||||||
|
|
||||||
async def test_bigsdb_profile_multiple_strings_same_string_twice(self, local_db, database_api, database_name, schema_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
async def test_bigsdb_profile_multiple_strings_same_string_twice(self, local_db, database_api, database_name, scheme_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
||||||
sequence = get_first_sequence_from_fasta(seq_path)
|
sequence = get_first_sequence_from_fasta(seq_path)
|
||||||
dummy_sequences = [[NamedString("seq1", sequence)], [NamedString("seq2", sequence)]]
|
dummy_sequences = [[NamedString("seq1", sequence)], [NamedString("seq2", sequence)]]
|
||||||
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, schema_id) as dummy_profiler:
|
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, scheme_id) as dummy_profiler:
|
||||||
async for named_profile in dummy_profiler.profile_multiple_strings(generate_async_iterable(dummy_sequences)):
|
async for named_profile in dummy_profiler.profile_multiple_strings(generate_async_iterable(dummy_sequences)):
|
||||||
name, profile = named_profile.name, named_profile.mlst_profile
|
name, profile = named_profile.name, named_profile.mlst_profile
|
||||||
assert profile is not None
|
assert profile is not None
|
||||||
@@ -134,10 +136,10 @@ class TestBIGSdbMLSTProfiler:
|
|||||||
assert profile.clonal_complex == expected_profile.clonal_complex
|
assert profile.clonal_complex == expected_profile.clonal_complex
|
||||||
assert profile.sequence_type == expected_profile.sequence_type
|
assert profile.sequence_type == expected_profile.sequence_type
|
||||||
|
|
||||||
async def test_bigsdb_profile_multiple_strings_exactmatch_fail_second_no_stop(self, local_db, database_api, database_name, schema_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
async def test_bigsdb_profile_multiple_strings_exactmatch_fail_second_no_stop(self, local_db, database_api, database_name, scheme_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
||||||
valid_seq = get_first_sequence_from_fasta(seq_path)
|
valid_seq = get_first_sequence_from_fasta(seq_path)
|
||||||
dummy_sequences = [[NamedString("seq1", valid_seq)], [NamedString("should_fail", gene_scrambler(valid_seq, 0.3))], [NamedString("seq3", valid_seq)]]
|
dummy_sequences = [[NamedString("seq1", valid_seq)], [NamedString("should_fail", gene_scrambler(valid_seq, 0.3))], [NamedString("seq3", valid_seq)]]
|
||||||
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, schema_id) as dummy_profiler:
|
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, scheme_id) as dummy_profiler:
|
||||||
async for name_profile in dummy_profiler.profile_multiple_strings(generate_async_iterable(dummy_sequences), True):
|
async for name_profile in dummy_profiler.profile_multiple_strings(generate_async_iterable(dummy_sequences), True):
|
||||||
name, profile = name_profile.name, name_profile.mlst_profile
|
name, profile = name_profile.name, name_profile.mlst_profile
|
||||||
|
|
||||||
@@ -151,11 +153,11 @@ class TestBIGSdbMLSTProfiler:
|
|||||||
assert profile.clonal_complex == expected_profile.clonal_complex
|
assert profile.clonal_complex == expected_profile.clonal_complex
|
||||||
assert profile.sequence_type == expected_profile.sequence_type
|
assert profile.sequence_type == expected_profile.sequence_type
|
||||||
|
|
||||||
async def test_bigsdb_profile_multiple_strings_nonexact_second_no_stop(self, local_db, database_api, database_name, schema_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
async def test_bigsdb_profile_multiple_strings_nonexact_second_no_stop(self, local_db, database_api, database_name, scheme_id, seq_path: str, feature_seqs_path: str, expected_profile: MLSTProfile, bad_profile: MLSTProfile):
|
||||||
valid_seq = get_first_sequence_from_fasta(seq_path)
|
valid_seq = get_first_sequence_from_fasta(seq_path)
|
||||||
dummy_sequences = [[NamedString("seq1", valid_seq)], [NamedString("should_fail", gene_scrambler(valid_seq, 0.3))], [NamedString("seq3", valid_seq)]]
|
dummy_sequences = [[NamedString("seq1", valid_seq)], [NamedString("should_fail", gene_scrambler(valid_seq, 0.3))], [NamedString("seq3", valid_seq)]]
|
||||||
|
|
||||||
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, schema_id) as dummy_profiler:
|
async with bigsdb.get_BIGSdb_MLST_profiler(local_db, database_api, database_name, scheme_id) as dummy_profiler:
|
||||||
async for named_profile in dummy_profiler.profile_multiple_strings(generate_async_iterable(dummy_sequences), False):
|
async for named_profile in dummy_profiler.profile_multiple_strings(generate_async_iterable(dummy_sequences), False):
|
||||||
name, profile = named_profile.name, named_profile.mlst_profile
|
name, profile = named_profile.name, named_profile.mlst_profile
|
||||||
|
|
||||||
@@ -183,12 +185,12 @@ class TestBIGSdbIndex:
|
|||||||
async with BIGSdbIndex() as bigsdb_index:
|
async with BIGSdbIndex() as bigsdb_index:
|
||||||
assert (await bigsdb_index.get_bigsdb_api_from_seqdefdb("pubmlst_bordetella_seqdef")) == "https://bigsdb.pasteur.fr/api"
|
assert (await bigsdb_index.get_bigsdb_api_from_seqdefdb("pubmlst_bordetella_seqdef")) == "https://bigsdb.pasteur.fr/api"
|
||||||
|
|
||||||
async def test_bigsdb_index_get_schemas_for_bordetella(self):
|
async def test_bigsdb_index_get_schemes_for_bordetella(self):
|
||||||
async with BIGSdbIndex() as index:
|
async with BIGSdbIndex() as index:
|
||||||
schemas = await index.get_schemas_for_seqdefdb(seqdef_db_name="pubmlst_bordetella_seqdef")
|
schemes = await index.get_schemes_for_seqdefdb(seqdef_db_name="pubmlst_bordetella_seqdef")
|
||||||
assert len(schemas.keys()) > 0
|
assert len(schemes.keys()) > 0
|
||||||
assert "MLST" in schemas
|
assert "MLST" in schemes
|
||||||
assert isinstance(schemas["MLST"], int)
|
assert isinstance(schemes["MLST"], int)
|
||||||
|
|
||||||
async def test_bigsdb_index_get_databases_has_only_seqdef(self):
|
async def test_bigsdb_index_get_databases_has_only_seqdef(self):
|
||||||
async with BIGSdbIndex() as index:
|
async with BIGSdbIndex() as index:
|
||||||
@@ -207,5 +209,6 @@ class TestBIGSdbIndex:
|
|||||||
async with await bigsdb_index.build_profiler_from_seqdefdb(local, "pubmlst_bordetella_seqdef", 3) as profiler:
|
async with await bigsdb_index.build_profiler_from_seqdefdb(local, "pubmlst_bordetella_seqdef", 3) as profiler:
|
||||||
assert isinstance(profiler, BIGSdbMLSTProfiler)
|
assert isinstance(profiler, BIGSdbMLSTProfiler)
|
||||||
profile = await profiler.profile_string(sequence)
|
profile = await profiler.profile_string(sequence)
|
||||||
|
assert isinstance(profile, MLSTProfile)
|
||||||
assert profile.clonal_complex == "ST-2 complex"
|
assert profile.clonal_complex == "ST-2 complex"
|
||||||
assert profile.sequence_type == "1"
|
assert profile.sequence_type == "1"
|
||||||
|
Reference in New Issue
Block a user