---
title: relationship
sidebarTitle: relationship
---

# `infrahub_sdk.node.relationship`

## Classes

### `RelationshipManagerBase`

Base class for :class:`RelationshipManager` and :class:`RelationshipManagerSync`.

A ``RelationshipManagerBase`` exposes a cardinality-many relationship as a list of
peers along with helpers to add, remove, or extend the set. Relationship managers are
initialized lazily: until :meth:`fetch` (on the async/sync subclasses) is called, the
members are not loaded and editing is not allowed.

**Attributes:**

- `name`: The name of the relationship slot on the parent node.
- `schema`: The schema describing the relationship.
- `branch`: The branch the relationship is bound to.
- `peers`: The current peer set.
- `initialized`: ``True`` once the manager has been populated with data.

**Methods:**

#### `peer_ids`

```python
peer_ids(self) -> list[str]
```

Return the IDs of all peers that have one.

**Returns:**

- list\[str]: The IDs of the peers, in insertion order.

#### `peer_hfids`

```python
peer_hfids(self) -> list[list[Any]]
```

Return the HFIDs of all peers that have one.

**Returns:**

- list\[list\[Any]]: The HFIDs of the peers as lists of components, in insertion order.

#### `peer_hfids_str`

```python
peer_hfids_str(self) -> list[str]
```

Return the HFIDs of all peers as separator-joined strings.

**Returns:**

- list\[str]: The HFIDs of the peers as ``Kind__part1__part2`` strings.

#### `has_update`

```python
has_update(self) -> bool
```

Return whether the peer set has been modified since initialization.

**Returns:**

- ``True`` after a successful :meth:`add`, :meth:`extend`, or :meth:`remove`.

#### `is_from_profile`

```python
is_from_profile(self) -> bool
```

Return whether this relationship was set from a profile.

The relationship is considered profile-sourced only when every peer is itself
sourced from a profile.

**Returns:**

- ``True`` when at least one peer exists and all peers are from a profile.

### `RelationshipManager`

Asynchronous manager for a cardinality-many relationship.

Extends :class:`RelationshipManagerBase` with the ability to populate and edit the
peer set against an :class:`InfrahubClient`: :meth:`fetch` resolves every peer in a
parallel batch and :meth:`add`, :meth:`extend`, and :meth:`remove` mutate the peer
list in memory. Peers are exposed as :class:`RelatedNode` instances and can be
accessed by index via ``manager[i]``.

**Methods:**

#### `fetch`

```python
fetch(self) -> None
```

Populate the peer set and resolve every peer to a full node.

When the manager is not yet initialized, the parent node is re-queried with this
relationship included so the peer list can be populated. The peers are then
fetched in a parallel batch grouped by kind and stored in the client store.

**Raises:**

- `Error`: If any peer is missing an ``id`` or ``typename`` and cannot be resolved.

#### `add`

```python
add(self, data: str | RelatedNode | dict) -> None
```

Add a new peer to this relationship.

The new peer is only added when its ID or HFID is not already present; duplicate
adds are silently ignored.

**Args:**

- `data`: The peer to add. Accepts an ID string, an
existing \:class\:`RelatedNode`, or a dict describing the peer (with ``id``
or ``hfid`` keys, plus optional relationship properties).

**Raises:**

- `UninitializedError`: If \:meth\:`fetch` has not been called on this manager yet.

#### `extend`

```python
extend(self, data: Iterable[str | RelatedNode | dict]) -> None
```

Add new peers to this relationship.

This is a convenience wrapper that calls :meth:`add` for every item in ``data``.
Items already present (by ID or HFID) are silently ignored.

**Args:**

- `data`: The peers to add, in any of the
formats accepted by \:meth\:`add`.

**Raises:**

- `UninitializedError`: If \:meth\:`fetch` has not been called on this manager yet.

#### `remove`

```python
remove(self, data: str | RelatedNode | dict) -> None
```

Remove a peer from this relationship.

The peer to remove is matched first by ID, then by HFID. When no match is found,
the call is a no-op.

**Args:**

- `data`: The peer to remove. Accepts an ID string, an
existing \:class\:`RelatedNode`, or a dict describing the peer.

**Raises:**

- `UninitializedError`: If \:meth\:`fetch` has not been called on this manager yet.
- `IndexError`: If the internal peer index is inconsistent with the lookup result.

### `RelationshipManagerSync`

Synchronous manager for a cardinality-many relationship.

Synchronous counterpart of :class:`RelationshipManager`. Extends
:class:`RelationshipManagerBase` with the ability to populate and edit the peer set
against an :class:`InfrahubClientSync`: :meth:`fetch` resolves every peer in a
parallel batch and :meth:`add`, :meth:`extend`, and :meth:`remove` mutate the peer
list in memory. Peers are exposed as :class:`RelatedNodeSync` instances and can be
accessed by index via ``manager[i]``.

**Methods:**

#### `fetch`

```python
fetch(self) -> None
```

Populate the peer set and resolve every peer to a full node.

When the manager is not yet initialized, the parent node is re-queried with this
relationship included so the peer list can be populated. The peers are then
fetched in a parallel batch grouped by kind and stored in the client store.

**Raises:**

- `Error`: If any peer is missing an ``id`` or ``typename`` and cannot be resolved.

#### `add`

```python
add(self, data: str | RelatedNodeSync | dict) -> None
```

Add a new peer to this relationship.

The new peer is only added when its ID or HFID is not already present; duplicate
adds are silently ignored.

**Args:**

- `data`: The peer to add. Accepts an ID string,
an existing \:class\:`RelatedNodeSync`, or a dict describing the peer (with
``id`` or ``hfid`` keys, plus optional relationship properties).

**Raises:**

- `UninitializedError`: If \:meth\:`fetch` has not been called on this manager yet.

#### `extend`

```python
extend(self, data: Iterable[str | RelatedNodeSync | dict]) -> None
```

Add new peers to this relationship.

This is a convenience wrapper that calls :meth:`add` for every item in ``data``.
Items already present (by ID or HFID) are silently ignored.

**Args:**

- `data`: The peers to add, in any of the
formats accepted by \:meth\:`add`.

**Raises:**

- `UninitializedError`: If \:meth\:`fetch` has not been called on this manager yet.

#### `remove`

```python
remove(self, data: str | RelatedNodeSync | dict) -> None
```

Remove a peer from this relationship.

The peer to remove is matched first by ID, then by HFID. When no match is found,
the call is a no-op.

**Args:**

- `data`: The peer to remove. Accepts an ID string,
an existing \:class\:`RelatedNodeSync`, or a dict describing the peer.

**Raises:**

- `UninitializedError`: If \:meth\:`fetch` has not been called on this manager yet.
- `IndexError`: If the internal peer index is inconsistent with the lookup result.
