diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..21638c1 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,24 @@ +name: CI + +on: [push, pull_request] + +jobs: + style: + name: Check style + runs-on: 'ubuntu-latest' + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - name: Install dependencies + run: python3 -m pip install ".[dev]" + + - name: Ruff checks + run: python3 -m ruff check . + + - name: isort checks + run: python3 -m isort --check . diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5ba9d71 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: +- repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.244 + hooks: + - id: ruff +- repo: https://github.com/pycqa/isort + rev: 5.6.4 + hooks: + - id: isort + args: ["--check"] diff --git a/.vscode/launch.json b/.vscode/launch.json index e1e5ce0..2a01a59 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,4 +18,4 @@ "module": "anyvar.restapi" } ] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 2b7e46d..371c111 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { "python.formatting.provider": "yapf" -} \ No newline at end of file +} diff --git a/bin/cv-load-timing b/bin/cv-load-timing index 593c892..1477d8a 100755 --- a/bin/cv-load-timing +++ b/bin/cv-load-timing @@ -4,20 +4,19 @@ import logging import os import sys -from biocommons.seqrepo import SeqRepo -from bioutils.exceptions import BioutilsError import coloredlogs import redis +import tqdm +from biocommons.seqrepo import SeqRepo +from bioutils.exceptions import BioutilsError from ga4gh.vrs import models from ga4gh.vrs.dataproxy import SeqRepoDataProxy from hgvs.exceptions import HGVSParseError -import tqdm from anyvar import AnyVar -from anyvar.translator import Translator from anyvar.extras.clinvarparser import ClinvarParser from anyvar.storage.redisobjectstore import RedisObjectStore - +from anyvar.translator import Translator _logger = logging.getLogger(__name__) @@ -30,7 +29,7 @@ def firstn(gen, n=None): yield e if i == n: break - + if __name__ == "__main__": @@ -55,7 +54,10 @@ if __name__ == "__main__": n_cvrec = 0 n_exc = 0 for cvrec in pbar: - #_logger.info(f"{cvrec.accession}; {cvrec.record_type}; {len(cvrec.hgvs_expressions)} hgvs expressions") + #_logger.info( + # f"{cvrec.accession}; {cvrec.record_type}; {len(cvrec.hgvs_expressions)} " + # "hgvs expressions" + # ) n_cvrec += 1 n_hgvs += len(cvrec.hgvs_expressions) if n_cvrec % 10 == 0: @@ -63,9 +65,11 @@ if __name__ == "__main__": for he in cvrec.hgvs_expressions: try: v = tlr.from_hgvs(he) - except (ValueError, HGVSParseError, AttributeError, KeyError, BioutilsError): + except ( + ValueError, HGVSParseError, AttributeError, KeyError, BioutilsError + ): v = models.Text(definition=he) _id = av.put_object(v) - #_logger.info(f"stored {_id} for {he}") + _logger.info(f"stored {_id} for {he}") _logger.info(f"{n_hgvs} hgvs expressions in {n_cvrec} clinvar records") diff --git a/docker-build b/docker-build index 7473cb8..3301ec2 100755 --- a/docker-build +++ b/docker-build @@ -10,5 +10,5 @@ tag=$(git describe --tags) e docker build -t $imagename:$tag "$@" . e docker push $imagename:$tag -e docker tag $imagename:$tag $imagename:latest -e docker push $imagename:latest +e docker tag $imagename:$tag $imagename:latest +e docker push $imagename:latest diff --git a/docker-compose.yml b/docker-compose.yml index d9af77f..349d515 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,7 +18,7 @@ services: - seqrepo-rest-service # - uta #environment: - # # UTA_DB_URL: + # # UTA_DB_URL: # # SEQREPO_REST_SERVICE_URL: redis: @@ -28,7 +28,7 @@ services: volumes: - anyvar_redis_vol:/data - seqrepo-rest-service: + seqrepo-rest-service: # Test: curl http://localhost:5000/seqrepo/1/sequence/refseq:NM_000551.3 expose: - 5000 @@ -37,7 +37,7 @@ services: image: biocommons/seqrepo-rest-service:latest volumes: - seqrepo_vol:/usr/local/share/seqrepo - + # uta: # # Test: # # psql -XAt postgres://anonymous@localhost/uta -c 'select count(*) from transcript' diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4a01f39 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[tool.ruff] +exclude = [ + "venv", + "build", + "dist", + "tests" +] + +line-length = 88 + +[tool.ruff.per-file-ignores] +"__init__.py" = ["F401", "E402"] +"uidoc.py" = ["E501"] + +[tool.isort] +group_by_package = true diff --git a/setup.cfg b/setup.cfg index 554afe5..0e1c1e8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,10 +32,13 @@ exclude = [options.extras_require] dev = - ipython + ruff + pre-commit + isort test = pytest pytest-cov + pytest-mock [aliases] @@ -47,12 +50,5 @@ universal = 1 [build_sphinx] all_files = 1 -# http://pep8.readthedocs.org/en/latest/intro.html#error-codes -[flake8] -max-line-length = 120 -exclude = tests/* -max-complexity = 10 -ignore = E129,E221,E241,E251,E303,W291 - [tool:pytest] addopts = --cov=anyvar --cov-report term-missing diff --git a/src/anyvar/anyvar.py b/src/anyvar/anyvar.py index f40dc16..6d54a09 100644 --- a/src/anyvar/anyvar.py +++ b/src/anyvar/anyvar.py @@ -3,22 +3,23 @@ """ -from collections.abc import MutableMapping import logging +from collections.abc import MutableMapping from ga4gh.core import ga4gh_identify from ga4gh.vrs import models, vrs_deref, vrs_enref from anyvar.translate.translate import _Translator - _logger = logging.getLogger(__name__) class AnyVar: def __init__(self, /, translator: _Translator, object_store: MutableMapping): if not isinstance(object_store, MutableMapping): - _logger.warning("AnyVar(object_store=) should be a mutable mapping; you're on your own") + _logger.warning( + "AnyVar(object_store=) should be a mutable mapping; you're on your own" + ) self.object_store = object_store self.translator = translator diff --git a/src/anyvar/extras/clinvarparser.py b/src/anyvar/extras/clinvarparser.py index 7400802..3604f64 100644 --- a/src/anyvar/extras/clinvarparser.py +++ b/src/anyvar/extras/clinvarparser.py @@ -3,13 +3,13 @@ import lxml.etree as le - _logger = logging.getLogger() class VariationArchive: def __init__(self, element): - assert element.tag == "VariationArchive", "Expected node type `VariationArchive`" + assert element.tag == "VariationArchive", \ + "Expected node type `VariationArchive`" self._element = element @property @@ -39,7 +39,7 @@ def record_type(self): @property def variation_name(self): return self._element.get("VariationName") - + @property def variation_type(self): return self._element.get("VariationType") @@ -47,7 +47,7 @@ def variation_type(self): @property def version(self): return self._element.get("Version") - + @property def xrefs(self): return [e.attrib for e in self._element.xpath(".//XRefList/XRef")] @@ -75,4 +75,7 @@ def clinvar_open(fp): import sys fn = sys.argv[1] for va in clinvar_open(fn): - print(f"{va.acv}\t{va.variation_name}\t{va.variation_type}\t{len(va.hgvs_expressions)}\t{len(va.xrefs)}") + print( + f"{va.acv}\t{va.variation_name}\t{va.variation_type}\t" + f"{len(va.hgvs_expressions)}\t{len(va.xrefs)}" + ) diff --git a/src/anyvar/restapi/_data/openapi.yaml b/src/anyvar/restapi/_data/openapi.yaml index d29b3f0..7527858 100644 --- a/src/anyvar/restapi/_data/openapi.yaml +++ b/src/anyvar/restapi/_data/openapi.yaml @@ -615,4 +615,3 @@ components: length: 248956422 alphabet: ACGMNRT added: 2016-08-27T21:17:00Z - diff --git a/src/anyvar/restapi/globals.py b/src/anyvar/restapi/globals.py index b939c3c..14c66f6 100644 --- a/src/anyvar/restapi/globals.py +++ b/src/anyvar/restapi/globals.py @@ -8,10 +8,11 @@ from typing import Any, Callable, Optional from flask import current_app -from ga4gh.vrs.dataproxy import create_dataproxy, _DataProxy -from anyvar.translate.translate import TranslatorSetupException +from ga4gh.vrs.dataproxy import _DataProxy, create_dataproxy -from anyvar.translate.variation_normalizer import VariationNormalizerRestTranslator +from anyvar.translate.translate import TranslatorSetupException +from anyvar.translate.variation_normalizer import \ + VariationNormalizerRestTranslator from ..anyvar import AnyVar from ..storage import create_storage diff --git a/src/anyvar/restapi/routes/allele.py b/src/anyvar/restapi/routes/allele.py index 8535a09..1ca7423 100644 --- a/src/anyvar/restapi/routes/allele.py +++ b/src/anyvar/restapi/routes/allele.py @@ -15,7 +15,9 @@ def put(body): except TranslationException: result["messages"].append(f"Unable to translate {defn}") except NotImplementedError: - result["messages"].append(f"Variation class for {defn} is currently unsupported.") + result["messages"].append( + f"Variation class for {defn} is currently unsupported." + ) else: v_id = av.put_object(v) result["object"] = v.as_dict() diff --git a/src/anyvar/restapi/routes/find_alleles.py b/src/anyvar/restapi/routes/find_alleles.py index 602868d..ecefb30 100644 --- a/src/anyvar/restapi/routes/find_alleles.py +++ b/src/anyvar/restapi/routes/find_alleles.py @@ -1,7 +1,7 @@ -from connexion import NoContent +from anyvar.storage.postgres import PostgresObjectStore from ..globals import get_anyvar -from anyvar.storage.postgres import PostgresObjectStore + def get_ga4gh_alias(seqrepo_data_proxy, accession): md = seqrepo_data_proxy.get_metadata(accession) diff --git a/src/anyvar/restapi/routes/info.py b/src/anyvar/restapi/routes/info.py index 2f4004d..86f8d2b 100644 --- a/src/anyvar/restapi/routes/info.py +++ b/src/anyvar/restapi/routes/info.py @@ -1,8 +1,6 @@ -from connexion import NoContent - -import anyvar import ga4gh.vrs +import anyvar def search(): diff --git a/src/anyvar/restapi/routes/sequence.py b/src/anyvar/restapi/routes/sequence.py index bedef63..f1f9f3f 100644 --- a/src/anyvar/restapi/routes/sequence.py +++ b/src/anyvar/restapi/routes/sequence.py @@ -1,7 +1,7 @@ import logging from ..globals import get_dataproxy -from .utils import get_sequence_ids, problem +from .utils import problem _logger = logging.getLogger(__name__) @@ -12,4 +12,3 @@ def get(alias, start=None, end=None): return problem(422, "Invalid coordinates: start > end") dp = get_dataproxy() return dp.get_sequence(alias, start, end), 200 - diff --git a/src/anyvar/restapi/routes/sequence_metadata.py b/src/anyvar/restapi/routes/sequence_metadata.py index 21ad44a..3baf7b9 100644 --- a/src/anyvar/restapi/routes/sequence_metadata.py +++ b/src/anyvar/restapi/routes/sequence_metadata.py @@ -1,10 +1,6 @@ import logging -from connexion import NoContent - from ..globals import get_dataproxy -from .utils import get_sequence_ids, problem - _logger = logging.getLogger(__name__) diff --git a/src/anyvar/restapi/routes/summary_statistics.py b/src/anyvar/restapi/routes/summary_statistics.py index 40fdd57..845ad6c 100644 --- a/src/anyvar/restapi/routes/summary_statistics.py +++ b/src/anyvar/restapi/routes/summary_statistics.py @@ -1,5 +1,6 @@ from ..globals import get_anyvar + def get(vartype): av = get_anyvar() if vartype == "substitution": diff --git a/src/anyvar/restapi/routes/text.py b/src/anyvar/restapi/routes/text.py index b99a120..b62ade6 100644 --- a/src/anyvar/restapi/routes/text.py +++ b/src/anyvar/restapi/routes/text.py @@ -1,5 +1,3 @@ -from connexion import NoContent - from ..globals import get_anyvar @@ -8,7 +6,7 @@ def put(body): request = body defn = request.pop("definition") v = av.create_text(defn) - id = av.put_object(v) + av.put_object(v) result = { "object": v.as_dict(), "messages": [], diff --git a/src/anyvar/restapi/routes/utils.py b/src/anyvar/restapi/routes/utils.py index 426a1d7..df46867 100644 --- a/src/anyvar/restapi/routes/utils.py +++ b/src/anyvar/restapi/routes/utils.py @@ -1,16 +1,14 @@ # taken from seqrepo-rest-service/src/seqrepo_rest_service/utils.py +import logging +import re from base64 import urlsafe_b64decode, urlsafe_b64encode from binascii import hexlify, unhexlify from http.client import responses as http_responses -import logging -import re import connexion - from bioutils.accessions import infer_namespaces - _logger = logging.getLogger(__name__) @@ -37,12 +35,12 @@ def get_sequence_id(sr, query): * A fully-qualified sequence alias (e.g., VMC:0123 or refseq:NM_01234.5) * A digest or digest prefix from VMC, TRUNC512, or MD5 * A sequence accession (without namespace) - + Returns None if not found; seq_id if only one match; raises - RuntimeError for ambiguous matches. + RuntimeError for ambiguous matches. """ - + seq_ids = get_sequence_ids(sr, query) if len(seq_ids) == 0: _logger.warning(f"No sequence found for {query}") @@ -59,7 +57,7 @@ def get_sequence_ids(sr, query): * A fully-qualified sequence alias (e.g., VMC:0123 or refseq:NM_01234.5) * A digest or digest prefix from VMC, TRUNC512, or MD5 * A sequence accession (without namespace) - + The first match will be returned. """ @@ -73,7 +71,9 @@ def get_sequence_ids(sr, query): def problem(status, message): - return connexion.problem(status=status, title=http_responses[status], detail=message) + return connexion.problem( + status=status, title=http_responses[status], detail=message + ) @@ -105,7 +105,7 @@ def _generate_nsa_options(query): if namespaces: nsa_options = [(ns, query) for ns in namespaces] return nsa_options - + # if hex, try md5 and TRUNC512 if re.match(r"^(?:[0-9A-Fa-f]{8,})$", query): nsa_options = [("MD5", query + "%")] diff --git a/src/anyvar/restapi/routes/variation.py b/src/anyvar/restapi/routes/variation.py index 7eef98c..ed5f4e8 100644 --- a/src/anyvar/restapi/routes/variation.py +++ b/src/anyvar/restapi/routes/variation.py @@ -5,7 +5,7 @@ def put(body): av = get_anyvar() - translator = vm.translator + translator = av.translator request = body @@ -34,4 +34,3 @@ def get(id): return v.as_dict(), 200 except KeyError: return NoContent, 404 - diff --git a/src/anyvar/restapi/routes/variationset.py b/src/anyvar/restapi/routes/variationset.py index 6b472ab..09472c7 100644 --- a/src/anyvar/restapi/routes/variationset.py +++ b/src/anyvar/restapi/routes/variationset.py @@ -19,16 +19,15 @@ def put(body): vo = models.VariationSet(members=defn["member_ids"]) vo._id = ga4gh_identify(vo) av.put_object(vo) - + result = { "messages": messages, "data": vo.as_dict(), } - + return result, 200 def get(id): av = get_anyvar() return av.get_object(id).as_dict(), 200 - diff --git a/src/anyvar/restapi/uidoc.py b/src/anyvar/restapi/uidoc.py index c7f5909..af919d9 100644 --- a/src/anyvar/restapi/uidoc.py +++ b/src/anyvar/restapi/uidoc.py @@ -26,12 +26,9 @@ - - + """ - - - diff --git a/src/anyvar/restapi/utils.py b/src/anyvar/restapi/utils.py index 0cb8b0c..0b37f21 100644 --- a/src/anyvar/restapi/utils.py +++ b/src/anyvar/restapi/utils.py @@ -1,14 +1,12 @@ """Provide miscellaneous helper functions for AnyVar web app""" +import importlib.resources import logging -from pathlib import Path import re -import importlib.resources import tempfile -from typing import Generator +from pathlib import Path from ga4gh.vrs import schema_path - _logger = logging.getLogger("anyvar_api") @@ -23,9 +21,14 @@ def generate_openapi_yaml() -> str: # TODO: jsonapi isn't implemented yet # "jsonapi.json": spec_dir + "/jsonapi.json", } - ref_re = re.compile(r"""^(\s+\$ref:\s+["']file:)(\w[^#]+)(#)""", re.MULTILINE) + ref_re = re.compile( + r"""^(\s+\$ref:\s+["']file:)(\w[^#]+)(#)""", re.MULTILINE + ) with open(spec_fn) as spec_f: - finished_spec = ref_re.sub(lambda m: m.group(1) + "//" + ref_map[m.group(2)] + m.group(3), spec_f.read()) + finished_spec = ref_re.sub( + lambda m: m.group(1) + "//" + \ + ref_map[m.group(2)] + m.group(3), spec_f.read() + ) return finished_spec diff --git a/src/anyvar/restapi/webapp.py b/src/anyvar/restapi/webapp.py index 0571388..1cf2737 100644 --- a/src/anyvar/restapi/webapp.py +++ b/src/anyvar/restapi/webapp.py @@ -7,7 +7,8 @@ from flask import Flask, redirect from anyvar.restapi.utils import get_tmp_openapi_yaml -from .uidoc import redoc_template, rapidoc_template + +from .uidoc import rapidoc_template, redoc_template def create_app() -> Flask: diff --git a/src/anyvar/storage/README-pg.md b/src/anyvar/storage/README-pg.md index 971f93b..d07fde1 100644 --- a/src/anyvar/storage/README-pg.md +++ b/src/anyvar/storage/README-pg.md @@ -1,3 +1,3 @@ docker pull postgres docker run -d --name anyvar-pg -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres -psql -h localhost -U postgres -p 5432 \ No newline at end of file +psql -h localhost -U postgres -p 5432 diff --git a/src/anyvar/storage/__init__.py b/src/anyvar/storage/__init__.py index 9ae0b2a..02812e0 100644 --- a/src/anyvar/storage/__init__.py +++ b/src/anyvar/storage/__init__.py @@ -2,7 +2,6 @@ import os from urllib.parse import urlparse - _logger = logging.getLogger(__name__) default_storage_uri = "memory:" @@ -40,7 +39,9 @@ def create_storage(uri=None): parsed_uri = urlparse(uri) if parsed_uri.scheme == "memory": - _logger.warning("Using memory storage; stored data will be discarded when process exits") + _logger.warning( + "Using memory storage; stored data will be discarded when process exits" + ) storage = dict() elif parsed_uri.scheme in ("", "file"): @@ -49,6 +50,7 @@ def create_storage(uri=None): elif parsed_uri.scheme == "redis": import redis + from .redisobjectstore import RedisObjectStore storage = RedisObjectStore(redis.Redis.from_url(uri)) diff --git a/src/anyvar/storage/pg_utility.py b/src/anyvar/storage/pg_utility.py index 4e0f131..8e7aab7 100644 --- a/src/anyvar/storage/pg_utility.py +++ b/src/anyvar/storage/pg_utility.py @@ -1,11 +1,12 @@ import contextlib -import weakref -import psycopg2 -import hgvs -from hgvs.dataproviders.uta import _parse_url import inspect import logging import os +import weakref + +import hgvs +import psycopg2 +from hgvs.dataproviders.uta import _parse_url _logger = logging.getLogger(__name__) @@ -68,14 +69,18 @@ def _connect(self): self.ensure_schema_exists() def _create_schema(self): - create_sql = "CREATE TABLE vrs_objects (id BIGSERIAL primary key, vrs_id text, vrs_object jsonb);" + create_sql = ( + "CREATE TABLE vrs_objects " + "(id BIGSERIAL primary key, vrs_id text, vrs_object jsonb);" + ) self._insert_one(create_sql) def ensure_schema_exists(self): # N.B. On AWS RDS, information_schema.schemata always returns zero rows r = self._fetchone( - "select exists(SELECT 1 FROM pg_catalog.pg_tables WHERE tablename = 'vrs_objects')" - ) + "select exists(" + "SELECT 1 FROM pg_catalog.pg_tables WHERE tablename = 'vrs_objects')" + ) if r[0]: return self._create_schema() diff --git a/src/anyvar/storage/postgres.py b/src/anyvar/storage/postgres.py index 40d04dc..3ba84e4 100644 --- a/src/anyvar/storage/postgres.py +++ b/src/anyvar/storage/postgres.py @@ -1,14 +1,9 @@ -import collections -import datetime -import functools -import logging -import os -import shelve import json -import zlib +import logging import ga4gh.vrs from ga4gh.core import is_pjs_instance + from .pg_utility import PostgresClient _logger = logging.getLogger(__name__) @@ -31,11 +26,16 @@ def __setitem__(self, name, value): name = str(name) # in case str-like d = value.as_dict() j = json.dumps(d) - self.conn._insert_one(f"insert into vrs_objects (vrs_id, vrs_object) values (%s,%s)", [name, j]) + self.conn._insert_one( + "insert into vrs_objects (vrs_id, vrs_object) values (%s,%s)", [name, j] + ) def __getitem__(self, name): name = str(name) # in case str-like - data = self.conn._fetchone(f"select vrs_object from vrs_objects where vrs_id = %s", [name]) + data = self.conn._fetchone( + "select vrs_object from vrs_objects where vrs_id = %s", + [name] + ) if data: data = data[0] typ = data["type"] @@ -54,19 +54,31 @@ def __del__(self): self._db.close() def __len__(self): - data = self.conn._fetchone(f"select count(*) as c from vrs_objects where vrs_object ->> 'type' = 'Allele'") + data = self.conn._fetchone( + "select count(*) as c from vrs_objects " + "where vrs_object ->> 'type' = 'Allele'" + ) return data[0] def deletion_count(self): - data = self.conn._fetchone(f"select count(*) as c from vrs_objects where length(vrs_object -> 'state' ->> 'sequence') = 0") + data = self.conn._fetchone( + "select count(*) as c from vrs_objects " + "where length(vrs_object -> 'state' ->> 'sequence') = 0" + ) return data[0] def substitution_count(self): - data = self.conn._fetchone(f"select count(*) as c from vrs_objects where length(vrs_object -> 'state' ->> 'sequence') = 1") + data = self.conn._fetchone( + "select count(*) as c from vrs_objects " + "where length(vrs_object -> 'state' ->> 'sequence') = 1" + ) return data[0] def insertion_count(self): - data = self.conn._fetchone(f"select count(*) as c from vrs_objects where length(vrs_object -> 'state' ->> 'sequence') > 1") + data = self.conn._fetchone( + "select count(*) as c from vrs_objects " + "where length(vrs_object -> 'state' ->> 'sequence') > 1" + ) return data[0] def __iter__(self): @@ -100,5 +112,3 @@ def find_alleles(self, ga4gh_accession_id, start, stop): data = self.conn._fetchall(query_str, [start, stop, ga4gh_accession_id]) return [vrs_object[0] for vrs_object in data if vrs_object] - - diff --git a/src/anyvar/storage/postgres_init.sql b/src/anyvar/storage/postgres_init.sql index c46c987..7434622 100644 --- a/src/anyvar/storage/postgres_init.sql +++ b/src/anyvar/storage/postgres_init.sql @@ -1,3 +1,3 @@ CREATE USER anyvar; CREATE DATABASE anyvar_db; -GRANT ALL PRIVILEGES ON DATABASE anyvar_db TO anyvar; \ No newline at end of file +GRANT ALL PRIVILEGES ON DATABASE anyvar_db TO anyvar; diff --git a/src/anyvar/storage/redisobjectstore.py b/src/anyvar/storage/redisobjectstore.py index 0286c76..b234bfc 100644 --- a/src/anyvar/storage/redisobjectstore.py +++ b/src/anyvar/storage/redisobjectstore.py @@ -7,7 +7,7 @@ class RedisObjectStore(collections.abc.MutableMapping): """Provides Redis-backed storage of VR objects - + The intention of this class is to provide a interface that is indistinguishable from a dictionary for the purposes of GA4GH objects. In particular, that means that the the value may be a VR @@ -26,7 +26,7 @@ def __init__(self, redis, models=ga4gh.vrs.models): def __contains__(self, name): name = name if isinstance(name, str) else str(name) return self.redis.exists(name) - + def __delitem__(self, name): name = name if isinstance(name, str) else str(name) @@ -119,7 +119,7 @@ def __setitem__(self, name, o): a0b = ros[a0id] assert a0 is not a0b assert a0 == a0b - + # get Location by id a0lb = ros[a0lid] assert a0l is not a0lb diff --git a/src/anyvar/storage/shelf.py b/src/anyvar/storage/shelf.py index 3fe93d8..9e48d8a 100644 --- a/src/anyvar/storage/shelf.py +++ b/src/anyvar/storage/shelf.py @@ -1,16 +1,12 @@ import collections -import datetime -import functools +import json import logging -import os import shelve -import json import zlib import ga4gh.vrs from ga4gh.core import is_pjs_instance - _logger = logging.getLogger(__name__) silos = "locations alleles haplotypes genotypes variationsets relations texts".split() @@ -23,9 +19,12 @@ def __init__(self, filename): _logger.debug(f"Opening {filename}") self._fn = filename self._db = shelve.open(self._fn) - + def __repr__(self): - return f"{self.__class__.__module__}.{self.__class__.__qualname__} filename={self._fn}>" + return ( + f"{self.__class__.__module__}.{self.__class__.__qualname__} " + f"filename={self._fn}>" + ) def __setitem__(self, name, value): assert is_pjs_instance(value), "ga4gh.vrs object value required" @@ -35,7 +34,7 @@ def __setitem__(self, name, value): e = j.encode("utf-8") c = zlib.compress(e) self._db[name] = c - + def __getitem__(self, name): name = str(name) # in case str-like data = json.loads(zlib.decompress(self._db[name]).decode("UTF-8")) @@ -62,5 +61,3 @@ def __iter__(self): def keys(self): return self._db.keys() - - diff --git a/src/anyvar/translate/__init__.py b/src/anyvar/translate/__init__.py index cfb28d0..3bd9276 100644 --- a/src/anyvar/translate/__init__.py +++ b/src/anyvar/translate/__init__.py @@ -1,3 +1,4 @@ """Provide proxy classes and other tools for translation middleware.""" -from .translate import _Translator, TranslatorConnectionException, TranslatorSetupException, TranslationException +from .translate import (TranslationException, TranslatorConnectionException, + TranslatorSetupException, _Translator) from .variation_normalizer import VariationNormalizerRestTranslator diff --git a/src/anyvar/translate/translate.py b/src/anyvar/translate/translate.py index c22ab8b..2135236 100644 --- a/src/anyvar/translate/translate.py +++ b/src/anyvar/translate/translate.py @@ -15,7 +15,9 @@ class TranslatorSetupException(Exception): class TranslatorConnectionException(Exception): - """Indicates failure to connect to translator instance (e.g. REST endpoing not responding)""" + """Indicates failure to connect to translator instance (e.g. REST endpoing not + responding) + """ class TranslationException(Exception): diff --git a/src/anyvar/translate/variation_normalizer.py b/src/anyvar/translate/variation_normalizer.py index 37afe28..80a1bbf 100644 --- a/src/anyvar/translate/variation_normalizer.py +++ b/src/anyvar/translate/variation_normalizer.py @@ -1,8 +1,9 @@ from typing import Dict + import requests from ga4gh.vrs import models as vrs_models -from . import _Translator, TranslatorConnectionException, TranslationException +from . import TranslationException, TranslatorConnectionException, _Translator class VariationNormalizerRestTranslator(_Translator): @@ -11,7 +12,8 @@ def __init__(self, endpoint_uri: str): """Initialize normalizer-based translator. :param endpoint_uri: base REST endpoint address - :raises TranslatorConnectionException: if endpoint doesn't respond to initial query + :raises TranslatorConnectionException: if endpoint doesn't respond to initial + query """ self.endpoint_base = endpoint_uri @@ -19,7 +21,8 @@ def __init__(self, endpoint_uri: str): resp = requests.get(openapi_docs) if resp.status_code != 200: raise TranslatorConnectionException( - f"Failed to get response from Variation Normalizer REST endpoint at {openapi_docs}" + f"Failed to get response from Variation Normalizer REST endpoint at " + f"{openapi_docs}" ) def _send_rest_request(self, request_url: str): @@ -40,7 +43,8 @@ def translate(self, var: str, **kwargs: Dict) -> vrs_models.Allele: resp = self._send_rest_request(req_url) if resp.status_code == 404: raise TranslatorConnectionException( - f"Failed to get response from Variation Normalizer REST endpoint at {req_url}" + f"Failed to get response from Variation Normalizer REST endpoint at " + f"{req_url}" ) elif resp.status_code == 500: raise TranslatorConnectionException( @@ -48,7 +52,8 @@ def translate(self, var: str, **kwargs: Dict) -> vrs_models.Allele: ) elif resp.status_code != 200: raise TranslatorConnectionException( - f"Variation Normalizer REST endpoint returned {resp.status_code} for {var}" + f"Variation Normalizer REST endpoint returned {resp.status_code} " + f"for {var}" ) resp_json = resp.json() diff --git a/src/anyvar/utils/formats.py b/src/anyvar/utils/formats.py index 893a153..9513333 100644 --- a/src/anyvar/utils/formats.py +++ b/src/anyvar/utils/formats.py @@ -1,6 +1,5 @@ import re - format_regexps = { "hgvs": [ # just the accession and variant type @@ -59,11 +58,10 @@ def infer_plausible_formats(o): if isinstance(o, list): return(set.intersection(infer_plausible_formats(elem) for elem in o)) - + if isinstance(o, str): return set(t for t, exprs in format_regexps.items() if any(e.match(o) for e in exprs)) raise RuntimeError("Cannot infer format of a " + type(o)) - diff --git a/src/anyvar/utils/orderedenum.py b/src/anyvar/utils/orderedenum.py index 25349ce..2989bea 100644 --- a/src/anyvar/utils/orderedenum.py +++ b/src/anyvar/utils/orderedenum.py @@ -3,17 +3,21 @@ class OrderedEnum(Enum): def __ge__(self, other): - assert self.__class__ is other.__class__, "OrderedEnum can only compare to OrderedEnum" + assert self.__class__ is other.__class__, \ + "OrderedEnum can only compare to OrderedEnum" return self.value >= other.value def __gt__(self, other): - assert self.__class__ is other.__class__, "OrderedEnum can only compare to OrderedEnum" + assert self.__class__ is other.__class__, \ + "OrderedEnum can only compare to OrderedEnum" return self.value > other.value def __le__(self, other): - assert self.__class__ is other.__class__, "OrderedEnum can only compare to OrderedEnum" + assert self.__class__ is other.__class__, \ + "OrderedEnum can only compare to OrderedEnum" return self.value <= other.value def __lt__(self, other): - assert self.__class__ is other.__class__, "OrderedEnum can only compare to OrderedEnum" + assert self.__class__ is other.__class__, \ + "OrderedEnum can only compare to OrderedEnum" return self.value < other.value diff --git a/tests/conftest.py b/tests/conftest.py index b2caa7c..c8c849e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ -import os import json +import os from pathlib import Path from typing import Dict diff --git a/tests/test_sequence.py b/tests/test_sequence.py index d04eff1..b695ab5 100644 --- a/tests/test_sequence.py +++ b/tests/test_sequence.py @@ -1,5 +1,6 @@ """Test sequence lookup and metadata endpoints.""" import json + import pytest