# Source code for opentelemetry.context

    # Copyright The OpenTelemetry Authors
    # SPDX-License-Identifier: Apache-2.0

    from __future__ import annotations

    import logging
    import os
    from contextvars import Token
    from uuid import uuid4

    # pylint: disable=wrong-import-position
    from opentelemetry.context.context import Context, _RuntimeContext  # noqa
    from opentelemetry.context.contextvars_context import ContextVarsRuntimeContext
    from opentelemetry.environment_variables import OTEL_PYTHON_CONTEXT

    logger = logging.getLogger(__name__)

    def _load_runtime_context() -> _RuntimeContext:
        """Initialize the RuntimeContext

        Returns:
            An instance of RuntimeContext.
        """
        configured_context = os.environ.get(OTEL_PYTHON_CONTEXT)
        if not configured_context:
            return ContextVarsRuntimeContext()

        # pylint: disable=import-outside-toplevel,no-name-in-module
        from opentelemetry.util._importlib_metadata import (  # noqa: PLC0415
            entry_points,
        )

        try:
            return next(
                iter(
                    entry_points(
                        group="opentelemetry_context", name=configured_context
                    )
                )
            ).load()()
        except Exception:  # pylint: disable=broad-exception-caught
            logger.exception(
                "Failed to load context: %s, falling back to contextvars_context",
                configured_context,
            )
            return ContextVarsRuntimeContext()

    _RUNTIME_CONTEXT = _load_runtime_context()

    def create_key(keyname: str) -> str:
        """To allow cross-cutting concern to control access to their local state,
        the RuntimeContext API provides a function which takes a keyname as input,
        and returns a unique key.
        Args:
            keyname: The key name is for debugging purposes and is not required to be unique.
        Returns:
            A unique string representing the newly created key.
        """
        return keyname + "-" + str(uuid4())

    def get_value(key: str, context: Context | None = None) -> object:
        """To access the local state of a concern, the RuntimeContext API
        provides a function which takes a context and a key as input,
        and returns a value.

        Args:
            key: The key of the value to retrieve.
            context: The context from which to retrieve the value, if None, the current context is used.

        Returns:
            The value associated with the key.
        """
        return context.get(key) if context is not None else get_current().get(key)

    def set_value(
        key: str, value: object, context: Context | None = None
    ) -> Context:
        """To record the local state of a cross-cutting concern, the
        RuntimeContext API provides a function which takes a context, a
        key, and a value as input, and returns an updated context
        which contains the new value.

        Args:
            key: The key of the entry to set.
            value: The value of the entry to set.
            context: The context to copy, if None, the current context is used.

        Returns:
            A new `Context` containing the value set.
        """
        if context is None:
            context = get_current()
        new_values = context.copy()
        new_values[key] = value
        return Context(new_values)

    def get_current() -> Context:
        """To access the context associated with program execution,
        the Context API provides a function which takes no arguments
        and returns a Context.

        Returns:
            The current `Context` object.
        """
        return _RUNTIME_CONTEXT.get_current()

    def attach(context: Context) -> Token[Context]:
        """Associates a Context with the caller's current execution unit. Returns
        a token that can be used to restore the previous Context.

        Args:
            context: The Context to set as current.

        Returns:
            A token that can be used with `detach` to reset the context.
        """
        return _RUNTIME_CONTEXT.attach(context)

    def detach(token: Token[Context]) -> None:
        """Resets the Context associated with the caller's current execution unit
        to the value it had before attaching a specified Context.

        Args:
            token: The Token that was returned by a previous call to attach a Context.
        """
        try:
            _RUNTIME_CONTEXT.detach(token)
        except Exception:  # pylint: disable=broad-exception-caught
            logger.exception("Failed to detach context")

    # FIXME This is a temporary location for the suppress instrumentation key.
    # Once the decision around how to suppress instrumentation is made in the
    # spec, this key should be moved accordingly.
    _ON_EMIT_RECURSION_COUNT_KEY = create_key("on_emit_recursion_count")
    _SUPPRESS_INSTRUMENTATION_KEY = create_key("suppress_instrumentation")
    _SUPPRESS_HTTP_INSTRUMENTATION_KEY = create_key(
        "suppress_http_instrumentation"
    )

    __all__ = [
        "Context",
        "attach",
        "create_key",
        "detach",
        "get_current",
        "get_value",
        "set_value",
    ]