Architecture ============ .. mermaid:: :title: Base classes classDiagram class hashable {} hashable --|> Node hashable --|> Connection Graph *-- Node : nodes Node *-- Connection: outgoing_connection Node *-- Connection: incoming_connection Node *-- NodeState: state NodeState *-- NodeOnlineState: online NodeState *-- Node: node NodeOnlineState --|> NodeIsOffline NodeOnlineState --|> NodeIsOnline Connection *-- ConnectionState: state ConnectionState *-- Connection: connection ConnectionState *-- ConnectionSetupState: setup ConnectionSetupState --|> ConnectionSetup ConnectionSetupState --|> ConnectionNotSetup class Graph { +bool is_directed +set[Node] nodes +Any data +Node add(node: Node) +Connection connect(source: Node, connection: Connection, destination: Node) +Node get_by_id(node_id: str) +set[Node] get_by_class(class_: type[Node]) +set[Node] get_by_data(predicate: Callable[[Any], bool]) +Node delete(node_id: str) -None internal_add_node(node: Node) -None internal_delete_node(node: Node) } class Node { +str identifier +data Any +NodeState state +set[Connection] outgoing_connection +set[Connection] incoming_connection +Connection connect(connection: Connection, destination: Node) +set[Node] get_outgoing_neighbors_by_connection_data(predicate: Callable[[Any], bool]) +set[Node] get_outgoing_neighbors_by_connection_type(type_: type[Connection]) +set[Node] get_outgoing_neighbors_by_node_data(predicate: Callable[[Any], bool]) +set[Node] get_outgoing_neighbors_by_node_type(type_: type[Node]) +set[Node] get_neighbors_by_connection_data(predicate: Callable[[Any], bool], direction: Literal["all", "outgoing", "incoming"]) +set[Node] get_neighbors_by_connection_type(type_: type[Connection], direction: Literal["all", "outgoing", "incoming"]) +set[Node] get_neighbors_by_node_data(predicate: Callable[[Any], bool], direction: Literal["all", "outgoing", "incoming"]) +set[Node] get_neighbors_by_node_type(type_: type[Node], direction: Literal["all", "outgoing", "incoming"]) +set[Node] get_incoming_neighbors_by_connection_data(predicate: Callable[[Any], bool]) +set[Node] get_incoming_neighbors_by_connection_type(type_: type[Connection]) +set[Node] get_incoming_neighbors_by_node_data(predicate: Callable[[Any], bool]) +set[Node] get_incoming_neighbors_by_node_type(type_: type[Node]) -None _post_init() -NodeIsOnline _ensure_online() } class NodeState { +Node node +NodeOnlineState online +bool is_online() } class NodeOnlineState { +NodeState state +bool is_online() } class NodeIsOffline { +Node attach(graph: Graph) } class NodeIsOnline { +Graph graph +set[Connection] outgoing_connection +set[Connection] incoming_connection +Node detach() +Connection connect(connection: Connection, destination: Node) +int delete_outgoing_connection_by_node(node: Node) +int delete_incoming_connection_by_node(node: Node) +set[Node] get_outgoing_neighbors_by_connection_data(predicate: Callable[[Any], bool]) +set[Node] get_outgoing_neighbors_by_connection_type(type_: type[Connection]) +set[Node] get_outgoing_neighbors_by_node_data(predicate: Callable[[Any], bool]) +set[Node] get_outgoing_neighbors_by_node_type(type_: type[Node]) +set[Node] get_incoming_neighbors_by_connection_data(predicate: Callable[[Any], bool]) +set[Node] get_incoming_neighbors_by_connection_type(type_: type[Connection]) +set[Node] get_incoming_neighbors_by_node_data(predicate: Callable[[Any], bool]) +set[Node] get_incoming_neighbors_by_node_type(type_: type[Node]) +bool is_online() -None _clear_connect(connection: Connection, destination: Node) -None check_connection_state(connection: Connection) -None _add_connection(connection: Connection, destination: Node) -tuple[set[Connection], int] _filter_connection_by_node(node: Node, connection: set[Connection], direction: Literal["in", "out"]) -ConnectionSetup _ensure_connection_setup(connection: Connection) } class Connection { +str identifier +data Any +ConnectionState state } class ConnectionState { +Connection connection +bool setup +bool is_setup() } class ConnectionSetupState { +ConnectionState state +bool is_setup() } class ConnectionNotSetup { +Connection setup(source: Node, destination: Node) } class ConnectionSetup { +Node source +Node destination } State ----- This library use class as state. Let’s take the ``Connection`` class for an example. A connection can be used by a ``Node`` or not. Let’s call a ``Connection`` not yet connected "Not setup". A ``Connection`` can then be ``Setup`` or ``Not setup``. When a ``Connection`` is not yet setup, it does not have a ``source`` or a ``destination``. But in the same state, it can also be setup and connected to a ``Node``. All of the properties or function that are related to a given state are stored in their own class. For the ``Connection`` classes, its "state storage" ``ConnectionState`` (that holds all state classes related to ``Connection``) store an ``online`` property of type ``ConnectionSetupState``. ``ConnectionSetupState`` is an abstract class with two inherited classes: ``ConnectionSetup``, that will be stored in ``ConnectionState`` when the ``Connection`` is setup, and ``ConnectionNotSetup`` when the ``Connection`` is not yet attached to a ``Node``. Node ---- ``Node`` has one state. If it is "online", it is attached to a ``Graph``. Else, it is "offline". Connection ---------- ``Connection`` has one state. If it is "setup", it is attached to a ``Node``. Else, it is "not setup".