# variants

Python API: `luxonis_train.variants`

The machinery behind the `variant` argument of nodes and models.

A variant is a named set of constructor arguments. A class declares its variants in
[VariantBase.get_variants](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/variants.md).
[VariantMeta](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/variants.md)
applies the selected set when a call creates an instance. A config thus selects a size with one word instead of a list of
parameters.

## Classes

### VariantBase

Base class for classes that
[VariantMeta](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/variants.md)
builds from variants.

A subclass declares its variants in
[get_variants](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/variants.md).
A subclass without variants overrides
[get_variants](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/variants.md)
to raise `NotImplementedError`, as
[BaseNode](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
does.

#### Methods

##### get_variants

```python
def get_variants() -> tuple[str, dict[str, Kwargs]]:
```

Get the default variant name and the available variants.

The keys of the dictionary are the variant names. Each value holds keyword arguments for the constructor of the class.
[VariantMeta](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/variants.md)
passes the arguments of the selected variant to `__init__`. The default variant name must be a key of the dictionary.

An implementation must return new dictionaries on each call, because
[VariantMeta](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/variants.md)
deletes the keys that a call replaces.

Returns

 * `tuple[str, dict[str, Kwargs]]`: The default variant name, and the variants with their constructor arguments.

Raises

 * `NotImplementedError`: When the class has no variants.

### VariantMeta

Metaclass that builds an instance from a named variant.

A call to a class with this metaclass accepts the keyword argument `variant`. The argument does not reach `__init__`. Its value
selects how the metaclass builds the instance:

 * `None`, `""`, or `"none"`: the metaclass calls `__init__` with the other arguments.
 * `"default"`: the metaclass selects the default variant from `get_variants`. When `get_variants` raises `NotImplementedError`,
   the metaclass logs a warning and calls `__init__` with the other arguments.
 * Any other name: the metaclass selects the variant of that name.

For a selected variant, the metaclass stores the variant name in `_variant`. Then it calls `__init__` with the parameters of the
variant and the other arguments. A keyword argument of the call replaces the variant parameter of the same name, and the metaclass
logs an info message for it. Without a selected variant, `_variant` keeps its class default `None`.

After `__init__`, the metaclass calls the `__post_init__` method of the instance when the class defines one. The class
registration comes from the `AutoRegisterMeta` base of `luxonis_ml`.

> **Example**
> ```pycon
>>> from luxonis_train.variants import VariantBase
>>> class Block(VariantBase, register=False):
...     def __init__(self, width: int = 1):
...         self.width = width
...
...     @staticmethod
...     def get_variants():
...         return "n", {"n": {"width": 8}, "s": {"width": 16}}
>>> Block(variant="default").width
8
>>> Block().width
1
```

## Functions

### add_variant_aliases

```python
def add_variant_aliases(variants: dict[str, Kwargs], aliases: dict[str, Collection[str]] | Literal['yolo'] = 'yolo') -> dict[str,
Kwargs]:
```

Add alias names to a dictionary of variants.

For each variant name in `aliases` that `variants` holds, the function adds an entry for each alias. The alias entry is the same dictionary object as the entry of the variant, not a copy. An alias replaces an entry of the same name. The function skips a name that `variants` does not hold.

> **Example**
> ```pycon
>>> add_variant_aliases({"n": {"width": 8}, "l": {"width": 64}})
{'n': {'width': 8}, 'l': {'width': 64},
 'nano': {'width': 8}, 'large': {'width': 64}}
>>> add_variant_aliases(
...     {"a": {"x": 1}}, {"a": ["alpha"], "b": ["beta"]}
... )
{'a': {'x': 1}, 'alpha': {'x': 1}}
```

Parameters

 * `variants` (`dict[str, Kwargs]`): The variants, keyed by name. The function adds the aliases to this dictionary in place.
 * `aliases` (`dict[str, Collection[str]] | Literal['yolo']`): Each variant name mapped to its aliases. `"yolo"` maps `"tiny"`,
   `"nano"`, `"small"`, `"medium"`, and `"large"` to their first letters, and each first letter back to its full name.

Returns

 * `dict[str, Kwargs]`: The `variants` dictionary itself, with the aliases.
