Source code for Karana.Core._KCore_Py

# Copyright (c) 2024-2026 Karana Dynamics Pty Ltd. All rights reserved.
#
# NOTICE TO USER:
#
# This source code and/or documentation (the "Licensed Materials") is
# the confidential and proprietary information of Karana Dynamics Inc.
# Use of these Licensed Materials is governed by the terms and conditions
# of a separate software license agreement between Karana Dynamics and the
# Licensee ("License Agreement"). Unless expressly permitted under that
# agreement, any reproduction, modification, distribution, or disclosure
# of the Licensed Materials, in whole or in part, to any third party
# without the prior written consent of Karana Dynamics is strictly prohibited.
#
# THE LICENSED MATERIALS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
# KARANA DYNAMICS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND
# FITNESS FOR A PARTICULAR PURPOSE.
#
# IN NO EVENT SHALL KARANA DYNAMICS BE LIABLE FOR ANY DAMAGES WHATSOEVER,
# INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, OR USE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, WHETHER IN CONTRACT, TORT,
# OR OTHERWISE ARISING OUT OF OR IN CONNECTION WITH THE LICENSED MATERIALS.
#
# U.S. Government End Users: The Licensed Materials are a "commercial item"
# as defined at 48 C.F.R. 2.101, and are provided to the U.S. Government
# only as a commercial end item under the terms of this license.
#
# Any use of the Licensed Materials in individual or commercial software must
# include, in the user documentation and internal source code comments,
# this Notice, Disclaimer, and U.S. Government Use Provision.

"""KCore contains a collection of classes that form core infrastructure for many other classes through Karana software.

Examples include Base and LockingBase which serve as base classes for most simulation-related objects.
"""

import datetime
from typing import TypeVar, cast, overload, TypeAlias, Union, Generic
from traceback import format_stack

# Define Json type alias before loading in pybind11
Json: TypeAlias = dict[str, Union[str, int, float, "Json"]]
from Karana.Core._KCore_pybind11_Py import *
from Karana.Core._KCore_pybind11_Py import deprecated as _deprecated


# Giving credit to Basilisk. See https://github.com/AVSLab/basilisk/blob/19e5538bed96141634fac4570b5b50abb01836a3/src/utilities/deprecated.py
@overload
def deprecated(name: str, removal_date: datetime.date | str, msg: str):
    """
    Print a deprecation message.

    Parameters
    ----------
    name : str
        Name of the class, function, etc. being deprecated.
    removal_date : datetime.date | str
        The date at which the deprecated class, function, etc. will be removed.
    msg : str
        A message telling the user how to fix their deprecated code.
    """
    ...  # pragma: no cover. Will not be run by code coverage.


@overload
def deprecated(removal_date: datetime.date | str, msg: str):
    """Use this decorator is used to mark functions or classes as deprecated.

    Usage::

        @deprecated.deprecated("2024-05-28", "Use MyNewClass")
        class MyClass:
            ...

    or::

        @deprecated.deprecated("2024-05-28", "myFun is unsafe now")
        def myFun(a, b):
            ...

    or::

        class ValidClass:

            @deprecated.deprecated("2024-05-28", "myMethod is slow, use myBetterMethod")
            def myMethod(self, a, b):
                ...

    Parameters
    ----------
    removal_date : datetime.date | str
        The date at which the deprecated class, function, etc. will be removed.
    msg : str
        A message telling the user how to fix their deprecated code.
    """
    ...  # pragma: no cover. Will not be run by code coverage.


def deprecated(*args, **_):
    """Use this decorator is used to mark functions or classes as deprecated.

    See overloaded function signatures for details.
    """
    if len(args) == 2:
        # Decorator
        def wrapper(func):
            name = f"{func.__module__}.{func.__qualname__}"
            removal_date = args[0]
            if isinstance(removal_date, str):
                removal_date = datetime.datetime.strptime(removal_date, r"%Y-%m-%d").date()
            msg = args[1]

            def innerWrapper(*args, **kwargs):
                deprecated(name, removal_date, msg)
                return func(*args, **kwargs)

            return innerWrapper

        return wrapper
    elif len(args) == 3:

        name = args[0].replace(")", "").replace("(", "")
        removal_date = args[1]
        if isinstance(removal_date, str):
            removal_date = datetime.datetime.strptime(removal_date, r"%Y-%m-%d").date()

        stack = "".join(format_stack()[:-1])
        _deprecated(name, str(removal_date), args[2] + "\nStack follows:\n" + stack)
    else:
        raise ValueError("Got an invalid number of arguments.")


T = TypeVar("T", bound=Base)


class CppWeakRef(CppWeakRefBase, Generic[T]):
    """Weak reference to C++ object.

    Use the get() method to return a Python object from the C++ object
    if it exists.
    """

    def __init__(self, base: T):
        """Create a CppWeakRef.

        Parameters
        ----------
        base : T
            Object to create a CppWeakRef to.
        """
        super().__init__(base)

[docs] def __call__(self) -> T | None: """Return a Python object for the C++ class if it exists, or None if it does not. Returns ------- T | None The Python object if the C++ object still exists. None if it does not. """ return cast(T, super().__call__())