Field Annotations

The annotations control how a field is loaded, generated or derived from external data. They are expressed directly on the dataclass / pydantic model attributes.

Overview

In FLYNC a field can stray away from standard yaml serializiation by being:

  • External - the value is read from or written to a separate file / folder.

  • Implied - the value is not stored but calculated on the fly using a defined strategy.

Both concepts are implemented by the External and Implied dataclasses. The behaviour of these dataclasses is further refined by three IntEnum strategy classes:

  • NamingStrategy - how the external file / folder is named.

  • OutputStrategy - how the external representation is organised (single file vs folder).

  • ImpliedStrategy - how an implied field is calculated.

Using External in a model

from flync.core.base_models import External, NamingStrategy, OutputStrategy
from flync.model.base_model import FLYNCBaseModel

class FLYNCGeneralConfig(FLYNCBaseModel):
    someip_config: Annotated[
            Optional[SOMEIPConfig],
            External(
                output_structure=OutputStrategy.FOLDER,
                naming_strategy=NamingStrategy.FIXED_PATH,
                path="someip",
            ),
        ] = Field(
            default=None,
            description="contains the SOME/IP config for the entire system.",
        )
  • path - location of the external resource relative to the current component, if left empty, this will be calculated from the naming_strategy attribute.

  • output_structure - SINGLE_FILE creates one file, FOLDER creates a directory containing multiple files.

  • naming_strategy - FIXED_PATH uses the explicit path; AUTO would derive the name from the field name.

Using Implied in a model

from flync.core.base_models import Implied, ImpliedStrategy
from flync.model.base_model import BaseModel

class ECU(FLYNCBaseModel, UniqueName):
    name: Annotated[
        str,
        Implied(strategy=ImpliedStrategy.FOLDER_NAME)
    ] = pydantic.Field()

When the model is instantiated, flync will compute name based on the folder name that contains the ECU definition.

Combining both annotations

A field can be declared as either External or Implied - they are mutually exclusive. If both are needed, split the logic into separate helper properties.

Example model

from pathlib import Path
from flync.core.base_models import External, Implied, NamingStrategy, OutputStrategy, ImpliedStrategy
from flync.model.base_model import BaseModel

class ECU(FLYNCBaseModel, UniqueName):
    name: Annotated[str, Implied(ImpliedStrategy.FOLDER_NAME)]
    ports: Annotated[List["ECUPort"], External()] = pydantic.Field(min_length=1)
    controllers: Annotated[List["Controller"], External()] = pydantic.Field()
    switches: Annotated[Optional[List["Switch"]], External()] = pydantic.Field(
        default=[]
    )
    topology: Annotated[
        "InternalTopology",
        External(),
    ] = pydantic.Field()
    info: Annotated[
        "MetadataECU",
        External(
            output_structure=OutputStrategy.SINGLE_FILE,
        ),
    ] = pydantic.Field()

Key points

  • Choose the appropriate NamingStrategy to control file naming.

  • Use OutputStrategy.FOLDER when a field naturally maps to multiple files (e.g. controllers).

  • ImpliedStrategy.FOLDER_NAME is handy for identifiers that follow the directory layout.

  • All strategy classes are defined in src/flync/helper_models.py - keep them imported from that module to avoid circular imports.