Adapters¶
Adapters translate NWB Schema Language to LinkML Schema.
Adapter - Base Adapter Classes
Namespaces - Top-level container of NWB namespace indices and schema
Schema - Individual NWB Schema files within a namespace
Classes - Root methods shared between classes and groups
Adapter classes for translating from NWB schema language to LinkML
- class Adapter¶
Abstract base class for adapters
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- abstract build() BuildResult¶
Generate the corresponding linkML element for this adapter
- get(name: str) Group | Dataset¶
Get the first item whose
neurodata_type_defmatchesnameConvenience wrapper around
walk_field_values()
- get_model_with_field(field: str) Generator[Group | Dataset, None, None]¶
Yield models that have a non-None value in the given field.
Useful during development to find all the ways that a given field is used.
- Parameters:
field (str) – Field to search for
- walk(input: BaseModel | dict | list) Generator[BaseModel | Any | None, None, None]¶
Iterate through all items in the given model.
Could be a staticmethod or a function, but bound to adapters to make it available to them :)
- walk_fields(input: BaseModel | dict | list, field: str | Tuple[str, ...]) Generator[Any, None, None]¶
Recursively walk input for fields that match
field- Parameters:
input (
pydantic.BaseModel) – Model to walk (or a list or dictionary to walk too)
Returns:
- model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}¶
A dictionary of computed field names and their corresponding ComputedFieldInfo objects.
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_fields: ClassVar[dict[str, FieldInfo]] = {}¶
Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].
This replaces Model.__fields__ from Pydantic V1.
- walk_field_values(input: BaseModel | dict | list, field: str, value: Any | None = None) Generator[BaseModel, None, None]¶
Recursively walk input for models that contain a
fieldas a direct child with a value matchingvalue- Parameters:
input (
pydantic.BaseModel) – Model to walkfield (str) – Name of field - unlike
walk_fields(), only one field can be givenvalue (Any) – Value to match for given field. If
None, return models that have the field
- Returns:
pydantic.BaseModelthe matching model
- class ArrayAdapter(dims: List[str | None] | List[List[str | None]], shape: List[str | None] | List[List[str | None]])¶
Adapter that generates a
ArrayExpression(or set of them) from a NWB dims/shape declaration- pivot_dims(dims: List[str | None] | List[List[str | None]] | None = None, shape: List[str | None] | List[List[str | None]] | None = None) List[Shape]¶
Pivot from a list of dims and a list of shape to a list of (dim, shape) tuples
- make_expression(shape: Shape) ArrayExpression¶
Create the corresponding array specification from a shape
- class BuildResult(schemas: ~typing.List[~linkml_runtime.linkml_model.meta.SchemaDefinition] = <factory>, classes: ~typing.List[~linkml_runtime.linkml_model.meta.ClassDefinition] = <factory>, slots: ~typing.List[~linkml_runtime.linkml_model.meta.SlotDefinition] = <factory>, types: ~typing.List[~linkml_runtime.linkml_model.meta.TypeDefinition] = <factory>, **_kwargs)¶
Container class for propagating nested build results back up to caller
- schemas: List[SchemaDefinition]¶
- classes: List[ClassDefinition]¶
- slots: List[SlotDefinition]¶
- types: List[TypeDefinition]¶
- class ClassAdapter(*, TYPE: T, cls: TI, parent: ClassAdapter | None = None)¶
Abstract adapter to class-like things in linkml, holds methods common to both DatasetAdapter and GroupAdapter
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- TYPE: T¶
The type that this adapter class handles
- cls: TI¶
- parent: ClassAdapter | None¶
- abstract build() BuildResult¶
Make this abstract so it can’t be instantiated directly.
Subclasses call
build_base()to get the basics true of both groups and datasets
- build_base(extra_attrs: List[SlotDefinition] | None = None) BuildResult¶
Build the basic class and attributes before adding any specific modifications for groups or datasets.
The main distinction in behavior for this method is whether this class has a parent class - ie this is one of the anonymous nested child datasets or groups within another group.
If the class has no parent, then…
Its name is inferred from its neurodata_type_def, fixed name, or neurodata_type_inc in that order
It is just built as normal class!
It will be indicated as a
tree_root(which will primarily be used to invert the translation for write operations)
If the class has a parent, then…
If it has a neurodata_type_def or inc, that will be used as its name, otherwise concatenate parent__child, eg.
TimeSeries__TimeSeriesDataA slot will also be made and returned with the BuildResult, which the parent will then have as one of its attributes.
- build_attrs(cls: Dataset | Group) List[SlotDefinition]¶
Pack the class attributes into a list of SlotDefinitions
- classmethod handle_dtype(dtype: List[CompoundDtype] | FlatDtype | ReferenceDtype | None) str¶
Get the string form of a dtype
- Parameters:
dtype (
DTypeType) – Dtype to stringify- Returns:
str
- build_name_slot() SlotDefinition¶
If a class has a name, then that name should be a slot with a fixed value.
If a class does not have a name, then name should be a required attribute
References
https://github.com/NeurodataWithoutBorders/nwb-schema/issues/552#issuecomment-1700319001
Returns:
- build_self_slot() SlotDefinition¶
If we are a child class, we make a slot so our parent can refer to us
- model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}¶
A dictionary of computed field names and their corresponding ComputedFieldInfo objects.
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_fields: ClassVar[dict[str, FieldInfo]] = {'TYPE': FieldInfo(annotation=~T, required=True), 'cls': FieldInfo(annotation=~TI, required=True), 'parent': FieldInfo(annotation=Union[ClassAdapter, NoneType], required=False, default=None)}¶
Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].
This replaces Model.__fields__ from Pydantic V1.
- class DatasetAdapter(*, cls: Dataset, parent: ClassAdapter | None = None)¶
Orchestrator class for datasets - calls the set of applicable mapping classes
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- build() BuildResult¶
Build the base result, and then apply the applicable mappings.
- match() Type[DatasetMap] | None¶
Find the map class that applies to this class
- Returns:
- Raises:
RuntimeError - if more than one map matches –
- model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}¶
A dictionary of computed field names and their corresponding ComputedFieldInfo objects.
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_fields: ClassVar[dict[str, FieldInfo]] = {'cls': FieldInfo(annotation=Dataset, required=True), 'parent': FieldInfo(annotation=Union[ClassAdapter, NoneType], required=False, default=None)}¶
Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].
This replaces Model.__fields__ from Pydantic V1.
- class GroupAdapter(*, TYPE: ~typing.Type = <class 'nwb_schema_language.datamodel.nwb_schema_pydantic.Group'>, cls: ~nwb_schema_language.datamodel.nwb_schema_pydantic.Group, parent: ~nwb_linkml.adapters.classes.ClassAdapter | None = None)¶
Adapt NWB Groups to LinkML Classes
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- build() BuildResult¶
Do the translation, yielding the BuildResult
- handle_container_group(cls: Group) BuildResult¶
Make a special LinkML children slot that can have any number of the objects that are of neurodata_type_inc class
Examples
- name: templates groups: - neurodata_type_inc: TimeSeries doc: TimeSeries objects containing template data of presented stimuli. quantity: '*' - neurodata_type_inc: Images doc: Images objects containing images of presented stimuli. quantity: '*'
- Parameters:
children (List[
Group]) – Child groups
- handle_container_slot(cls: Group) BuildResult¶
Handle subgroups that contain arbitrarily numbered classes,
eg. each of the groups in
Examples
name: trials neurodata_type_inc: TimeIntervals doc: Repeated experimental events that have a logical grouping. quantity: ‘?’
name: invalid_times neurodata_type_inc: TimeIntervals doc: Time intervals that should be removed from analysis. quantity: ‘?’
neurodata_type_inc: TimeIntervals doc: Optional additional table(s) for describing other experimental time intervals. quantity: ‘*’
- build_subclasses() BuildResult¶
Build nested groups and datasets
Create ClassDefinitions for each, but then also create SlotDefinitions that will be used as attributes linking the main class to the subclasses
- model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}¶
A dictionary of computed field names and their corresponding ComputedFieldInfo objects.
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_fields: ClassVar[dict[str, FieldInfo]] = {'TYPE': FieldInfo(annotation=Type, required=False, default=<class 'nwb_schema_language.datamodel.nwb_schema_pydantic.Group'>), 'cls': FieldInfo(annotation=Group, required=True), 'parent': FieldInfo(annotation=Union[ClassAdapter, NoneType], required=False, default=None)}¶
Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].
This replaces Model.__fields__ from Pydantic V1.
- class NamespacesAdapter(*, namespaces: Namespaces, schemas: List[SchemaAdapter], imported: List[NamespacesAdapter] = None)¶
Translate a NWB Namespace to a LinkML Schema
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- namespaces: Namespaces¶
- schemas: List[SchemaAdapter]¶
- imported: List[NamespacesAdapter]¶
- classmethod from_yaml(path: Path) NamespacesAdapter¶
Create a NamespacesAdapter from a nwb schema language namespaces yaml file.
Also attempts to provide imported implicitly imported schema (using the namespace key, rather than source, eg. with hdmf-common)
- build(skip_imports: bool = False, progress: AdapterProgress | None = None) BuildResult¶
Build the NWB namespace to the LinkML Schema
- find_type_source(name: str) SchemaAdapter¶
Given some neurodata_type_inc, find the schema that it’s defined in.
Rather than returning as soon as a match is found, check all
- populate_imports() None¶
Populate the imports that are needed for each schema file
This function adds a string version of imported schema assuming the generated schema will live in the same directory. If the path to the imported schema needs to be adjusted, that should happen elsewhere (eg in
LinkMLProvider) because we shouldn’t know about directory structure or anything like that here.
- to_yaml(base_dir: Path) None¶
Build the schemas, saving them to
yamlfiles according to theirname- Parameters:
base_dir (
Path) – Directory to saveyamlfiles
- property needed_imports: Dict[str, List[str]]¶
List of other, external namespaces that we need to import. Usually provided as schema with a namespace but not a source
- Returns:
[‘needed_import_0’, …]}
- Return type:
{‘namespace_name’
- schema_namespace(name: str) str | None¶
Inverse of
namespace_schemas()- given a schema name, get the namespace it’s in
- model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}¶
A dictionary of computed field names and their corresponding ComputedFieldInfo objects.
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_fields: ClassVar[dict[str, FieldInfo]] = {'imported': FieldInfo(annotation=List[NamespacesAdapter], required=False, default_factory=list), 'namespaces': FieldInfo(annotation=Namespaces, required=True), 'schemas': FieldInfo(annotation=List[SchemaAdapter], required=True)}¶
Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].
This replaces Model.__fields__ from Pydantic V1.
- class SchemaAdapter(*, path: Path, groups: List[Group] = None, datasets: List[Dataset] = None, imports: List[SchemaAdapter | str] = None, namespace: str | None = None, version: str | None = None)¶
An individual schema file in nwb_schema_language
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- imports: List[SchemaAdapter | str]¶
- build() BuildResult¶
Make the LinkML representation for this schema file
Things that will be populated later - id (but need to have a placeholder to instantiate) - version
- property created_classes: List[Type[Group | Dataset]]¶
All the group and datasets created in this schema
- property needed_imports: List[str]¶
Classes that need to be imported from other namespaces
TODO: - Need to also check classes used in links/references
- model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}¶
A dictionary of computed field names and their corresponding ComputedFieldInfo objects.
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_fields: ClassVar[dict[str, FieldInfo]] = {'datasets': FieldInfo(annotation=List[Dataset], required=False, default_factory=list), 'groups': FieldInfo(annotation=List[Group], required=False, default_factory=list), 'imports': FieldInfo(annotation=List[Union[SchemaAdapter, str]], required=False, default_factory=list), 'namespace': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='String of containing namespace. Populated by NamespacesAdapter'), 'path': FieldInfo(annotation=Path, required=True), 'version': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Version of schema, populated by NamespacesAdapter since individual schema files dont know their version in NWB Schema Lang')}¶
Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].
This replaces Model.__fields__ from Pydantic V1.