Object Mapping

Every value that lives inside a FLYNC workspace — whether it is the root model, a nested ECU, a list of controllers, or a single scalar — is tracked in two parallel dictionaries on FLYNCWorkspace:

This page explains how those two dictionaries are built during loading and how to query them at runtime.


Object IDs

An ObjectId is a plain dot-separated string that encodes the full path from the root model to a value.

Segment

Meaning

Example ID fragment

field_name

Named attribute on a model

ecus

key

Concrete dict key (resolved at load time)

ecus.gateway

0, 1, …

Numeric list index (see List Item IDs and ListObjectsMode)

ecus.gateway.controllers.0

name_value

Optional name-based alias for a list item (see List Item IDs and ListObjectsMode)

ecus.gateway.controllers.eth_ctrl

The root model itself is stored under the empty string "".

Note

available_flync_nodes() returns schema-level paths that use {} and [] as wildcards. The IDs stored in the workspace use concrete keys and indices that are resolved when the files are actually parsed. See Discovering Node Paths for the distinction.


List Item IDs and ListObjectsMode

When the workspace encounters a list (a SequenceNode in the YAML or a folder-based External list on disk), each item needs one or more ObjectId values so it can be retrieved individually. The list_objects_mode setting on WorkspaceConfiguration controls which IDs are generated via add_list_item_object_path().

class ListObjectsMode(*values)

Bases: IntFlag

Flags controlling how list items are keyed in the workspace object map.

Flags can be combined with |. The default is INDEX | NAME.

Attributes:
INDEX: Register each list item under its zero-based integer index

(e.g. controllers.0).

NAME: Register each list item under its name — the file/directory stem

for folder-based lists, or the model’s name attribute for inline YAML lists. Items without a name are skipped.

INDEX = 1
NAME = 2
FLYNCWorkspace.add_list_item_object_path(item_name, current_object_paths, idx)

Build the object path(s) for a single list item.

Depending on list_objects_mode, the item may be registered under its numeric index, its name, or both:

  • INDEX: appends the zero-based integer index as a path segment.

  • NAME: appends item_name as an additional path segment when the name is non-empty. For external (folder-based) lists the name comes from the file/directory stem; for inline lists it comes from the model’s name attribute.

Both flags are active by default, so a list item is accessible under two IDs simultaneously (e.g. controllers.0 and controllers.my_ctrl).

Args:
item_name (str | None): Name of the list item, or None /

empty string when the item has no name.

current_object_paths (list[str]): Parent path(s) to extend. idx (int): Zero-based position of the item in the list.

Returns:

list[str]: New list of object paths for this item.

Modes

Mode

Effect

INDEX only

Each item is registered under its zero-based integer index. controllers.0, controllers.1, …

NAME only

Each item is registered under its name (the name attribute on the model, or the file/directory stem for folder-based lists). Items without a name are silently skipped. controllers.eth_ctrl, controllers.can_ctrl, …

INDEX | NAME (default)

Both IDs are registered for the same item. The item is reachable under either path. controllers.0 and controllers.eth_ctrl

Source of the name

The name used for NAME mode depends on where the list lives:

  • Folder-based External lists — the name is the file or directory stem (everything before the first . in the filename). This is derived from sub_item_path.stem as the directory is iterated.

  • Inline YAML SequenceNode lists — the name is the ``name`` attribute of the validated Pydantic model at that index (getattr(model[idx], "name", None)). If the model has no name field the item gets an index-only ID even when NAME mode is active.

Configuring the mode

Pass a custom WorkspaceConfiguration when loading the workspace:

from flync.sdk.context.workspace_config import WorkspaceConfiguration, ListObjectsMode
from flync.sdk.workspace.flync_workspace import FLYNCWorkspace

# Index-only — useful when item names are not stable
config = WorkspaceConfiguration(
    list_objects_mode=ListObjectsMode.INDEX,
)
ws = FLYNCWorkspace.load_workspace("my_config", "/path/to/config", config)

# Name-only — useful when indices may shift across reloads or for easier object lookup for manual users
config = WorkspaceConfiguration(
    list_objects_mode=ListObjectsMode.NAME,
)

# Both (the default)
config = WorkspaceConfiguration(
    list_objects_mode=ListObjectsMode.INDEX | ListObjectsMode.NAME,
)

Example — dual IDs in practice

Given a workspace whose controllers/ directory contains eth_ctrl.flync.yaml and the default INDEX | NAME mode:

ws = FLYNCWorkspace.load_workspace("cfg", "/path/to/config")

# Both of these refer to the same SemanticObject
by_index = ws.get_object("ecus.gateway.controllers.0")
by_name  = ws.get_object("ecus.gateway.controllers.eth_ctrl")

assert by_index.model is by_name.model  # same validated instance

Source Types

class SourceRef(uri: str, range: Range)

Bases: object

Reference to the source location of a semantic object.

Attributes:

uri (str): Document URI where the object is defined. range (Range): The range within the document.

uri: str
range: Range
class Range(start: Position, end: Position)

Bases: object

Represents a range between two positions in a document.

Attributes:

start (Position): The start position of the range. end (Position): The end position of the range.

start: Position
end: Position
class Position(line: int, character: int)

Bases: object

Represents a position in a text document.

For objects backed by a YAML file both line and character are 1-based, derived from ruamel.yaml start_mark / end_mark by adding 1 to the 0-based mark offsets.

For objects that have no YAML source (e.g. implied or externally loaded objects without a resolved file) both fields are 0, acting as a sentinel meaning “no location available”.

Attributes:

line (int): 1-based line number, or 0 when no source is available. character (int): 1-based character offset, or 0 when no source is

available.

line: int
character: int
class SemanticObject(id: ObjectId, model: BaseModel)

Bases: object

Wrapper around a validated semantic model.

Attributes:

id (ObjectId): Identifier of the semantic object. model (BaseModel): The validated Pydantic model.

class ObjectId

A string-based unique identifier for a semantic object in the workspace.

alias of str


Runtime Retrieval

Once the workspace is loaded, four methods expose the object and source maps.

List all object IDs

FLYNCWorkspace.list_objects() list[ObjectId]

Return a list of all ObjectIds present in the workspace.

Returns:
list[ObjectId]:

List of object identifiers.

ws = FLYNCWorkspace.load_workspace("my_config", "/path/to/config")

for oid in ws.list_objects():
    print(oid)
# ""
# "ecus"
# "ecus.gateway"
# "ecus.gateway.controllers.0"        ← index-based ID
# "ecus.gateway.controllers.eth_ctrl" ← name-based ID (same object)
# ...

Retrieve a semantic object

FLYNCWorkspace.get_object(id: ObjectId) SemanticObject

Retrieve a semantic object by its ObjectId.

Args:
id (ObjectId):

Identifier of the semantic object.

Returns:
SemanticObject:

The requested semantic object.

obj = ws.get_object("ecus.gateway")
print(obj.model)   # EcuConfig instance
print(obj.id)      # "ecus.gateway"

Retrieve the source location

FLYNCWorkspace.get_source(id: ObjectId) SourceRef

Retrieve the source reference for a given ObjectId.

Args:
id (ObjectId):

Identifier of the object.

Returns:
SourceRef:

The source reference associated with the object.

src = ws.get_source("ecus.gateway")
print(src.uri)              # "ecus/gateway/ecu_metadata.flync.yaml"
print(src.range.start)      # Position(line=1, character=1)  ← 1-based (YAML-backed)
print(src.range.end)        # Position(line=42, character=1)

Note

Position values are 1-based for objects loaded from a YAML file (ruamel.yaml marks are shifted by +1). Objects that have no YAML source (implied or externally loaded without a resolved file) carry Position(line=0, character=0) as a sentinel.

Look up objects by file position

FLYNCWorkspace.objects_at(uri: str, line: int, character: int) list[ObjectId]

Return the list of ObjectIds located at the specified position in a document.

Args:
uri (str):

Document URI.

line (int):

1-based line number, consistent with the Position values stored during YAML parsing.

character (int):

1-based character offset within the line.

Returns:
list[ObjectId]:

List of object identifiers at the given position.

This is the primary entry point for language-server features such as hover and go-to-definition. Given a document URI and a cursor position, it returns every ObjectId whose source range contains that position.

ids = ws.objects_at(
    uri="ecus/gateway/ecu_metadata.flync.yaml",
    line=10,
    character=5,
)
for oid in ids:
    obj = ws.get_object(oid)
    print(oid, "→", type(obj.model).__name__)

Note

objects_at uses 1-based line and character numbers, matching the Position values stored during YAML parsing. Pass line=0, character=0 to query objects with no YAML source.


Object Path Helpers

These utility methods are used internally during loading but are also available for tooling that needs to build or resolve object paths at runtime.

FLYNCWorkspace.document_id_from_path(doc_path: Path) str

Return the workspace-relative string identifier for a document path.

Args:

doc_path (Path): An absolute path to a document file.

Returns:

str: The path relative to the workspace root, as a string.

static FLYNCWorkspace.new_object_path(current_path: str, new_object_name: int | str) str

Extend a dot-separated object path with a new segment.

Args:

current_path (str): The existing dot-separated path. new_object_name (int | str): The segment to append.

Returns:

str: The extended path string.

FLYNCWorkspace.update_objects_path(current_paths: list[str], new_object_name: str) list[str]

Extend every path in a list with a new segment.

Args:

current_paths (list[str]): Existing dot-separated paths. new_object_name (str): The segment to append to each path.

Returns:

list[str]: New list of extended path strings.

FLYNCWorkspace.fill_path_from_object(model_object: FLYNCBaseModel, object_path: str) str

Replace placeholder segments in an object path with concrete keys.

Traverses the workspace’s root model following object_path, substituting [] with the actual list index and {} with the actual dict key when model_object is found.

Args:

model_object (FLYNCBaseModel): The model instance to locate. object_path (str): Dot-separated path containing [] or {}

placeholders.

Returns:
str: The resolved dot-separated path with concrete index/key

values.


Data structure summary

FLYNCWorkspace
├── objects: Dict[ObjectId, SemanticObject]
│              │               │
│              │               └── .model  (validated Pydantic value)
│              │               └── .id     (same as the key)
│              │
│              ├── "ecus.gateway.controllers.0"        ─┐ both point to the
│              └── "ecus.gateway.controllers.eth_ctrl" ─┘ same SemanticObject
│                   (generated by add_list_item_object_path via ListObjectsMode)
│
└── sources: Dict[ObjectId, SourceRef]
               │               │
               │               └── .uri    (workspace-relative file path)
               │               └── .range  ─┬─ .start  Position(line, character)  ← 1-based for YAML; (0,0) if no source
               │                            └─ .end    Position(line, character)  ← 1-based for YAML; (0,0) if no source
               │
               └── key: same ObjectId used in objects
                    (one entry per ID, so index and name both have a SourceRef)