Source code for cosapp.utils.pull_variables

from __future__ import annotations
import logging
from typing import Any, Union, Collection, Dict, TYPE_CHECKING

if TYPE_CHECKING:
    from cosapp.systems import System

logger = logging.getLogger(__name__)


[docs] def pull_variables( child: System, pulling: Union[str, Collection[str], Dict[str, str]], ) -> None: """Pull variables from child to the parent. Parameters ---------- child: System `System` exposing variables to its parent API. pulling [str | collection[str] | dict[str, str]]: Map of child ports to pulled ports at the parent system level. """ from cosapp.systems import System from cosapp.ports.port import BasePort, Port from cosapp.ports.connectors import BaseConnector from cosapp.utils.naming import CommonPorts parent: System = child.parent if parent is None: raise AttributeError( f"Can't pull variables from orphan System {child.name!r}" ) method_map = { CommonPorts.INWARDS.value: 'add_inward', CommonPorts.OUTWARDS.value: 'add_outward', CommonPorts.MODEVARS_IN.value: 'add_inward_modevar', CommonPorts.MODEVARS_OUT.value: 'add_outward_modevar', } def log_debug(parent_attr, child_attr) -> str: logger.debug( f"{parent_attr} has been duplicated from {child_attr}" f" - including validation range and scope." ) def copy_variable( child: System, port_name: str, child_var: str, parent_var: str, value: Any, ) -> None: """Copy variable `child_var` from `child` into `parent`, as `parent_var`.""" child_port: BasePort = child[port_name] parent_port: BasePort = parent[port_name] lock_status = parent._locked parent._locked = False # Call `add_inward`, `add_outward`, etc., depending on context add_to_parent = getattr(parent, method_map[port_name]) add_to_parent(parent_var, value) parent._locked = lock_status # Copy full variable detail in parent port parent_port.copy_variable_from(child_port, child_var, parent_var) log_debug( f"{parent.name}.{parent_var}", f"{parent.name}.{child.name}.{child_var}", ) name_mapping = BaseConnector.format_mapping(pulling) for child_attr_name, parent_attr_name in name_mapping.items(): child_attr = getattr(child, child_attr_name) if isinstance(child_attr, Port): if parent_attr_name not in parent: pulled_port = child_attr.copy(parent_attr_name) parent._add_port(pulled_port) log_debug( f"Port {pulled_port.contextual_name}", f"{parent.name}.{child_attr.contextual_name}", ) else: pulled_port = getattr(parent, parent_attr_name) parent.connect(child_attr, pulled_port) else: # inwards, outwards, or mode variables if isinstance(child_attr, BasePort): # Pulling all variables port_name = child_attr.name parent_port = getattr(parent, port_name) for varname, value in child_attr.items(): if varname not in parent_port: copy_variable(child, port_name, varname, varname, value) parent.connect(child_attr, parent_port, list(child_attr)) else: # Pulling individual variable var = child.name2variable[child_attr_name] port_name = var.mapping.name if parent_attr_name not in parent[port_name]: copy_variable(child, port_name, child_attr_name, parent_attr_name, child_attr) parent.connect(child[port_name], parent[port_name], {child_attr_name: parent_attr_name})