Adding a resource type
The resource types GAIn understands are not a fixed list. Each one is a resource implementation — a class that knows how to describe a resource of that type, compute its statistics, and render its HTML summary page — and implementations are discovered through a Python entry-point group. A package installed alongside GAIn can add a type without any change to GAIn itself.
This is the extension seam for a new kind of resource; adding a new annotator is a different seam, with its own entry-point group.
The interface
An implementation subclasses
GenomicResourceImplementation,
whose constructor takes the
GenomicResource it wraps. Five
members are abstract, and they divide into two jobs:
Describing the resource.
get_info()
and
get_statistics_info()
return the HTML for the resource’s summary and statistics pages.
calc_info_hash()
returns a digest of everything get_info depends on, so a page is only
re-rendered when its inputs changed.
Computing statistics.
create_statistics_build_tasks()
returns the task-graph tasks that compute this resource’s statistics, and
calc_statistics_hash()
digests the inputs those tasks read — it is what lets grr_manage skip a
resource whose statistics are already current.
The concrete
files
property should report every file the implementation reads. A caching or
mirroring repository builds its fetch list from it, so a file left out is a
file that may be missing from a cached copy. (Publishing works off the
resource’s manifest instead, so it is unaffected.)
Registering
The entry-point group is gain.genomic_resources.implementations. Its keys
are resource type names — the type field in a resource’s
genomic_resource.yaml — and its values point at the builder for that
type. A builder is any callable taking a GenomicResource and returning an
implementation, so an implementation class whose constructor takes exactly
that is its own builder.
GAIn’s own types are registered this way in core/pyproject.toml. The
genome type is the smallest complete example:
[project.entry-points."gain.genomic_resources.implementations"]
genome = "gain.genomic_resources.implementations.reference_genome_impl:ReferenceGenomeImplementation"
A third-party package declares its own type the same way, in its own
pyproject.toml:
[project.entry-points."gain.genomic_resources.implementations"]
my_resource_type = "my_package.my_impl:MyResourceImplementation"
from gain.genomic_resources import GenomicResource
from gain.genomic_resources.resource_implementation import (
GenomicResourceImplementation,
)
class MyResourceImplementation(GenomicResourceImplementation):
"""Resource implementation for my_resource_type."""
def __init__(self, resource: GenomicResource):
super().__init__(resource)
@property
def files(self) -> set[str]:
return {self.config["filename"]}
def get_info(self, **kwargs):
...
def get_statistics_info(self, **kwargs):
...
def calc_info_hash(self) -> bytes:
...
def calc_statistics_hash(self) -> bytes:
...
def create_statistics_build_tasks(self, **kwargs):
...
Once the package is installed, grr_manage and the repository browser
handle resources of that type with no further configuration.
Looking a builder up
get_resource_implementation_builder() is the
lookup GAIn itself uses. It consults the in-process registry first and falls
back to the entry points, loading and caching whatever it finds; it returns
None for a type nothing has registered.
register_implementation() adds a builder to the
in-process registry directly, without an entry point. That is the right tool
for a test, or for a type defined in the same script that uses it; it is not
a substitute for the entry point in a package meant to be installed, because
it only takes effect once the registering module has been imported.
from gain.genomic_resources import (
get_resource_implementation_builder,
register_implementation,
)
register_implementation("my_resource_type", MyResourceImplementation)
builder = get_resource_implementation_builder("my_resource_type")
impl = builder(grr.get_resource("my/resource/id"))
A note on the shipped registrations: two keys may point at the same class.
cnv_collection and fragment_score both map to
FragmentScoreImplementation because the first is a deprecated spelling
kept registered for repositories outside our control — opening one warns.
Nothing prevents a third-party package from registering a type name GAIn
already uses; the entry-point group is flat, so prefer a name qualified by
your project.
API
- class gain.genomic_resources.resource_implementation.GenomicResourceImplementation(genomic_resource: GenomicResource)[source]
Base class used by resource implementations.
Resources are just a folder on a repository. Resource implementations are classes that know how to use the contents of the resource.
- abstractmethod calc_statistics_hash() bytes[source]
Compute the statistics hash.
This hash is used to decide whether the resource statistics should be recomputed.
- collect_index_info() tuple[tuple[str, ...], tuple[str, ...]][source]
Collect resource info for FTS index building.
Returns a (header, row) pair where header contains field names and row contains the corresponding values for this resource. Label keys/values are appended after the fixed fields.
Raises
ValueErrorif a label key cannot name an index field – every implementation reaches the index through here, and the index build reports a raise from here against this one resource (gain#464).An override that contributes further fields must call
super()and append to what it returns. This is the only place a label key is checked against the names the index reserves: the build’s own re-check sees the finished header, in which an implementation’s fields legitimately appear, so it cannot tell a field from a label (gain#542). A field added by an override belongs inGR_INDEX_NON_LABEL_COLUMNS.
- abstractmethod create_statistics_build_tasks(**kwargs: Any) list[TaskDesc][source]
Create tasks for calculating resource statistics for task graph.
- property files: set[str]
Return a list of resource files the implementation utilises.
- get_config() dict[source]
The resource’s configuration.
As read from the resource at construction; an implementation that validates its configuration replaces it with the validated form, and answers that here.
- abstractmethod get_info(**kwargs: Any) str[source]
Construct the contents of the implementation’s HTML info page.
- abstractmethod get_statistics_info(**kwargs: Any) str[source]
Construct the contents of the implementation’s HTML statistics info page.
- reload_statistics() ResourceStatistics | None[source]
Drop the cached statistics and reload via
get_statistics().For after the statistics were rebuilt on disk. Answers what
get_statistics()answers:Noneunless the implementation overrides it.
- property resource_id: str
The id of the resource this implementation wraps.
- gain.genomic_resources.register_implementation(resource_type: str, builder: Callable[[GenomicResource], GenomicResourceImplementation]) None[source]
Register a resource type with a given builder function.
The builder has to be a builder function which takes a genomic resource and returns a ready to use implementation. The type is the type of resource to which this builder will be mapped. This is usually the “type” field in the resource’s config.
- gain.genomic_resources.get_resource_implementation_builder(resource_type: str) Callable[[GenomicResource], GenomicResourceImplementation] | None[source]
Return an implementation builder for a certain resource type.
If the builder is not registered, then it will search for an entry point in the found implementations list. If an entry point is found, it will be loaded and registered and returned.