Source code for gain.genomic_resources.gene_models.gene_models_factory

from __future__ import annotations

import os
from typing import TYPE_CHECKING, Any

from gain import logging
from gain.genomic_resources.memo import Memo, config_memo_key

if TYPE_CHECKING:
    from gain.genomic_resources.gene_models.gene_models import GeneModels
    from gain.genomic_resources.repository import (
        GenomicResource,
        GenomicResourceRepo,
    )

logger = logging.getLogger(__name__)

_RESOURCE_CACHE: Memo[tuple[str, str, str], GeneModels] = Memo()
_FILE_CACHE: Memo[tuple[str, str], GeneModels] = Memo()


def _root_relative(path: str) -> str:
    """Return ``path`` as a name relative to the filesystem root.

    This API takes local paths that may point anywhere -- and its three
    paths (the models, the gene mapping and the chromosome mapping) need
    not share a directory, so the ``dirname``/``basename`` split its
    reference-genome and gene-set siblings use does not fit. Rooting the
    synthetic resource at ``/`` instead keeps every name relative to the
    resource, which is what resource file names must be (gain#467).
    """
    return os.path.abspath(path).lstrip("/")


[docs] def build_gene_models_from_file( file_name: str, file_format: str | None = None, gene_mapping_file_name: str | None = None, chrom_mapping_file_name: str | None = None, ) -> GeneModels: """Load gene models from local filesystem.""" # pylint: disable=import-outside-toplevel from gain.genomic_resources.fsspec_protocol import ( build_local_resource, ) from .gene_models import GeneModels config: dict[str, Any] = { "type": "gene_models", "filename": _root_relative(file_name), } if file_format: config["format"] = file_format if gene_mapping_file_name: config["gene_mapping"] = _root_relative(gene_mapping_file_name) if chrom_mapping_file_name is not None: config["chrom_mapping"] = { "filename": _root_relative(chrom_mapping_file_name), } # Keyed on the whole config so that every config-shaping # argument -- present and future -- participates in the key. return _FILE_CACHE.get_or_build( (file_name, config_memo_key(config)), lambda: GeneModels(build_local_resource("/", config)))
[docs] def build_gene_models_from_resource( resource: GenomicResource | None, ) -> GeneModels: """Build the gene models of a genomic resource. The returned object may not be loaded. Calls with the same resource return the same object, so an earlier caller may have loaded it. Parameters ---------- resource : GenomicResource | None A resource of type ``gene_models``. Returns ------- GeneModels The gene models of the resource. Check ``is_loaded()`` or call ``load()`` before any query. Raises ------ ValueError If ``resource`` is ``None`` or is not of type ``gene_models``. """ # pylint: disable=import-outside-toplevel from .gene_models import GeneModels if resource is None: raise ValueError(f"missing resource {resource}") if resource.get_type() != "gene_models": logger.error( "trying to open a resource %s of type " "%s as gene models", resource.resource_id, resource.get_type()) raise ValueError(f"wrong resource type: {resource.resource_id}") return _RESOURCE_CACHE.get_or_build( resource.get_memo_key(), lambda: GeneModels(resource))
[docs] def build_gene_models_from_resource_id( resource_id: str, grr: GenomicResourceRepo | None = None, ) -> GeneModels: """Build the gene models of the resource with a given id. The returned object may not be loaded. Calls that find the same resource return the same object, so an earlier caller may have loaded it. Parameters ---------- resource_id : str The id of a resource of type ``gene_models`` in the repository. grr : GenomicResourceRepo | None The repository that resolves ``resource_id``. When it is ``None``, the function builds the default repository with ``build_genomic_resource_repository()``. Returns ------- GeneModels The gene models of the resource. Check ``is_loaded()`` or call ``load()`` before any query. Raises ------ FileNotFoundError If a protocol-backed repository has no resource with this id. ValueError If a group repository has no resource with this id, or if the resource is not of type ``gene_models``. """ # pylint: disable=import-outside-toplevel from gain.genomic_resources.repository_factory import ( build_genomic_resource_repository, ) if grr is None: grr = build_genomic_resource_repository() return build_gene_models_from_resource(grr.get_resource(resource_id))