Karana.KUtils.Prefab
====================

.. py:module:: Karana.KUtils.Prefab

.. autoapi-nested-parse::

   Prefab base class and associated classes/functions.



Attributes
----------

.. autoapisummary::

   Karana.KUtils.Prefab.ConfigType
   Karana.KUtils.Prefab.ContextType
   Karana.KUtils.Prefab.ParamsType


Classes
-------

.. autoapisummary::

   Karana.KUtils.Prefab.Config
   Karana.KUtils.Prefab.Context
   Karana.KUtils.Prefab.Params
   Karana.KUtils.Prefab.PrefabDS
   Karana.KUtils.Prefab.Prefab


Module Contents
---------------

.. py:class:: Config(/, **data: Any)

   Bases: :py:obj:`Karana.KUtils.DataStruct.DataStruct`, :py:obj:`Karana.KUtils.DataStruct.NestedBaseMixin`


   Base class for Prefab Config.


.. py:class:: Context(/, **data: Any)

   Bases: :py:obj:`Karana.KUtils.DataStruct.DataStruct`, :py:obj:`Karana.KUtils.DataStruct.NestedBaseMixin`


   Base class for Prefab Context.


.. py:class:: Params(/, **data: Any)

   Bases: :py:obj:`Karana.KUtils.DataStruct.DataStruct`, :py:obj:`Karana.KUtils.DataStruct.NestedBaseMixin`


   Base class for Prefab Params.


.. py:data:: ConfigType

.. py:data:: ContextType

.. py:data:: ParamsType

.. py:class:: PrefabDS(/, **data: Any)

   Bases: :py:obj:`Karana.KUtils.DataStruct.DataStruct`, :py:obj:`Karana.KUtils.DataStruct.NestedBaseMixin`, :py:obj:`Karana.KUtils.DataStruct.IdMixin`, :py:obj:`Generic`\ [\ :py:obj:`ConfigType`\ , :py:obj:`ContextType`\ , :py:obj:`ParamsType`\ ]


   DataStruct for a Prefab.

   Classes derived from Prefab may derive from this and override toDS/fromDS as desired. However,
   this should work for most Prefabs as is.

   :param name: Name of the instance.
   :type name: str
   :param config: Config for the Prefab.
   :type config: SerializeAsAny[Config]
   :param context: Context for the Prefab.
   :type context: SerializeAsAny[Context]
   :param params: Params for the Prefab.
   :type params: SerializeAsAny[Params]
   :param parent: Name of parent for this prefab relative to the first prefab that was not
                  added by an addChildPrefab method.
   :type parent: str
   :param children: Children Prefabs of this Prefab.
   :type children: list[SerializeAsAny[DataStruct]]
   :param class_name: The class that this DataStruct represents. Used to create a new instance
                      of the class from this DataStruct.
   :type class_name: PyClassDS


   .. py:attribute:: name
      :type:  str


   .. py:attribute:: config
      :type:  pydantic.SerializeAsAny[ConfigType]


   .. py:attribute:: context
      :type:  pydantic.SerializeAsAny[ContextType]


   .. py:attribute:: params
      :type:  pydantic.SerializeAsAny[ParamsType]


   .. py:attribute:: parent
      :type:  str


   .. py:attribute:: children_raw
      :type:  list[pydantic.SerializeAsAny[Karana.KUtils.DataStruct.DataStruct]]
      :value: None



   .. py:attribute:: class_name
      :type:  Karana.KUtils.DataStruct.PyClassDS


   .. py:property:: children
      :type: list[PrefabDS[Any, Any, Any]]


      Get the children Prefabs.

      :returns: The children Prefabs.
      :rtype: list[PrefabDS[Any, Any, Any]]


   .. py:method:: toPrefab(parent_or_top: Prefab[Any, Any, Any] | None, context: ContextType | None = None) -> Prefab[Any, Any, Any]

      Convert this PrefabDS to an instance of the associated Prefab.

      This will also create instances of any children Prefabs if applicable.

      :param parent_or_top: The parent prefab or top_prefab. First, we will try to find the parent string
                            from the PrefabDS on this value. If it exists, we will use that as the parent.
                            Otherwise, we will use this as the parent directly. If None, then we will assume
                            the Prefab being created is the top-level Prefab.
      :type parent_or_top: Prefab[Any, Any, Any] | None
      :param context: Optional context to override what was deserialized. If None, then use what was
                      deserialized.
      :type context: ContextType | None = None

      :returns: An instance of the associated Prefab.
      :rtype: Prefab[Any, Any, Any]



.. py:class:: Prefab(name: str, config: ConfigType, context: ContextType, params: ParamsType, parent_prefab: Prefab[Any, Any, Any] | None = None)

   Bases: :py:obj:`Karana.Core.BaseWithVars`, :py:obj:`Generic`\ [\ :py:obj:`ConfigType`\ , :py:obj:`ContextType`\ , :py:obj:`ParamsType`\ ]


   The Prefab class holds a prefab for a simulation.

   Prefabs typically consist of one or more of the following:
   * Bodies
   * Models
   * Other prefabs

   .. attribute:: config

      The configuration for the prefab.

      :type: ConfigType

   .. attribute:: context

      The context for the prefab.

      :type: ContextType

   .. attribute:: params

      The parameters for the Prefab.

      :type: ParamsType


   .. py:attribute:: config
      :type:  ConfigType


   .. py:attribute:: context
      :type:  ContextType


   .. py:attribute:: params
      :type:  ParamsType


   .. py:property:: parent
      :type: Prefab[Any, Any, Any] | None


      Returns the parent prefab of this prefab.

      :returns: The parent prefab of this prefab if it exists.
      :rtype: "Prefab[Any, Any, Any] | None"


   .. py:method:: runBeforeInitialSetParent()

      Add any logic/commands that should run before the parent Prefab is set to this method.

      This method runs during construction just before the parent Prefab is set.



   .. py:method:: checkParentCompatible(parent: Prefab[Any, Any, Any] | None) -> bool

      Check whether the parent Prefab this Prefab is becoming a child of is compatible.

      :param parent: The parent Prefab this Prefab is becoming a child of. Can be None if there
                     is no parent.
      :type parent: Prefab | None

      :returns: True if the parent prefab is compatible, False otherwise.
      :rtype: bool



   .. py:method:: checkChildCompatible(child: Prefab[Any, Any, Any]) -> bool

      Check whether Prefab becoming a child of this Prefab is compatible.

      :param child: The Prefab becoming a child of this Prefab.
      :type child: Prefab

      :returns: True if the child prefab is compatible, False otherwise.
      :rtype: bool



   .. py:method:: addChildPrefabs() -> None

      Add child prefabs to this prefab.

      Override this method and add any child prefabs needed by this prefab.



   .. py:method:: addMultibodyObjects() -> None

      Add any multibody objects used by this prefab.

      Override this method and add any multibody objects (e.g., PhysicalBodys,
      Nodes, etc.) used by this prefab.



   .. py:method:: addKModels() -> None

      Add KModels needed by this prefab.

      Override this method and add any KModels needed by this prefab.



   .. py:method:: connectKModels() -> None

      Add any connections needed by KModels.

      Override this method and add logic to connect KModels
      in this prefab to other KModels.



   .. py:method:: addBody(parent_body: Karana.Dynamics.PhysicalBody, child_body: Karana.Dynamics.PhysicalBody | Karana.Dynamics.SOADyn_types.BodyDS) -> Karana.Dynamics.PhysicalBody

      Add a body to this Prefab.

      If this body already exists, just ensure it has the correct parent. Otherwise,
      create it with the correct parent.

      :param parent_body: The parent body to attach the new body to.
      :type parent_body: PhysicalBody
      :param child_body: The child_body to add. If BodyDS, then a new body is created;
                         otherwise, we check this has the correct parent and return it.
      :type child_body: PhysicalBody | BodyDS

      :returns: The body that was either checked or created.
      :rtype: PhysicalBody



   .. py:method:: addNode(parent_body: Karana.Dynamics.PhysicalBody, node: Karana.Dynamics.Node | Karana.Dynamics.SOADyn_types.NodeDS) -> Karana.Dynamics.Node

      Add a node to this Prefab.

      If this node already exists, just ensure it has the correct parent. Otherwise,
      create it with the correct parent.

      :param parent_body: The parent node to attach the new node to.
      :type parent_body: PhysicalBody
      :param child_node: The child_node to add. If NodeDS, then a new node is created;
                         otherwise, we check this has the correct parent and return it.
      :type child_node: Node | NodeDS

      :returns: The node that was either checked or created.
      :rtype: Node



   .. py:method:: toDS() -> PrefabDS[ConfigType, ContextType, ParamsType]

      Create a PrefabDS from this Prefab.

      :returns: The DataStruct that represents this Prefab.
      :rtype: PrefabDS



   .. py:method:: fromDS(data_struct: PrefabDS[ConfigType, ContextType, ParamsType], parent_or_top: Prefab[Any, Any, Any] | None, *_, **kwargs) -> Self
      :classmethod:


      Convert the PrefabDS to an instance of this Prefab.

      This will also create instances of the associated children if applicable.

      :param data_struct: The PrefabDS to create an instance of this Prefab from.
      :type data_struct: PrefabDS
      :param parent_or_top: The parent prefab or top_prefab. First, we will try to find the parent string
                            from the PrefabDS on this value. If it exists, we will use that as the parent.
                            Otherwise, we will use this as the parent directly. If None, then we will assume
                            the Prefab being created is the top-level Prefab.
      :type parent_or_top: Prefab[Any, Any, Any] | None

      :returns: An instance of this Prefab.
      :rtype: Self



   .. py:method:: requestFromHierarchy[T](path: str, fn: Callable[[Prefab[Any, Any, Any]], T | None], path_root: Prefab[Any, Any, Any] | None = None) -> list[T]

      Make a request to the current hierarchy of prefabs.

      This works by finding all the prefabs in the hierarchy that match the given
      path as searched from the path_root. If the path_root is None, then the root
      of the Prefab hierarchy is used. The provided `fn` is run on all the returned
      Prefab's, and any non-None values returned from it are combined into a list and
      returned.

      :param path: The path to use when finding prefabs in the hierarchy. This supports
                   filesystem-like syntax, so globbing, wildcards, etc. can be used.
      :type path: str
      :param fn: The function to run on each Prefab matching path from the hierarchy.
      :type fn: Callable[[Prefab[Any, Any, Any]], T | None]
      :param path_root: The root to search from. If None is provided, then the root of the
                        hierarchy is used.
      :type path_root: "Prefab[Any, Any, Any] | None"

      :returns: A list of objects returned by user provided function mapped over
                the Prefabs matching the path query.
      :rtype: list[T]



   .. py:method:: requestUniqueFromHierarchy[T](path: str, fn: Callable[[Prefab[Any, Any, Any]], T | None], path_root: Prefab[Any, Any, Any] | None = None) -> T

      Make a request to the current hierarchy of prefabs.

      This works by finding all the prefabs in the hierarchy that match the given
      path as searched from the path_root. If the path_root is None, then the root
      of the Prefab hierarchy is used. The provided `fn` is run on all the returned
      Prefabs, if one, unique non-None value is returned from applying `fn` to these
      Prefabs, then it is returned. If there is not one, unique non-None value, then
      an error message is thrown.

      :param path: The path to use when finding prefabs in the hierarchy. This supports
                   filesystem-like syntax, so globbing, wildcards, etc. can be used.
      :type path: str
      :param fn: The function to run on each Prefab matching path from the hierarchy.
      :type fn: Callable[[Prefab[Any, Any, Any]], T | None]
      :param path_root: The root to search from. If None is provided, then the root of the
                        hierarchy is used.
      :type path_root: "Prefab[Any, Any, Any] | None"

      :returns: A unique object returned by the user provided function mapped over
                the Prefabs matching the path query.
      :rtype: T



   .. py:method:: requestClosestFromHierarchy[T](path: str, fn: Callable[[Prefab[Any, Any, Any]], T | None], path_root: Prefab[Any, Any, Any] | None = None) -> T

      Make a request to the current hierarchy of prefabs.

      This works by finding all the prefabs in the hierarchy that match the given
      path as searched from the path_root. If the path_root is None, then the root
      of the Prefab hierarchy is used. The provided `fn` is run on all the returned
      Prefabs. Then, the one that is closest is returned. If there is a tie for the
      closest or None are returned, then an error is throw.

      :param path: The path to use when finding prefabs in the hierarchy. This supports
                   filesystem-like syntax, so globbing, wildcards, etc. can be used.
      :type path: str
      :param fn: The function to run on each Prefab matching path from the hierarchy.
      :type fn: Callable[[Prefab[Any, Any, Any]], T | None]
      :param path_root: The root to search from. If None is provided, then the root of the
                        hierarchy is used.
      :type path_root: "Prefab[Any, Any, Any] | None"

      :returns: The closest object returned by the user provided function mapped over
                the Prefabs matching the path query.
      :rtype: T



