Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Licensed under the MIT License.

from ._load_configuration import load_configuration_from_env
from .configuration import Configuration, _Configurable
from .configuration import Configuration, _Configurable, _RootConfigurable
from ._configuration_protocol import _ConfigurationProtocol, _DictConfigurable
from ._resolve import _resolve
from ._utils import (
Expand Down Expand Up @@ -31,6 +31,7 @@
"_try_set",
"_resolve",
"_Configurable",
"_RootConfigurable",
"_DictConfigurable",
"coerce_bool",
"coerce_int",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
from .configuration import Configuration

from ._logging import _configure_logging
from ._utils import _xpath
from ._resolve import _resolve


def load_configuration_from_env(
Expand All @@ -20,11 +18,6 @@ def load_configuration_from_env(
:param defaults: A mapping of default configuration values.
:return: A Configuration object containing the resolved configuration.
"""
local_vars = dict(env_vars)

resolved = _resolve(local_vars, defaults or {})
config = Configuration(resolved)
_configure_logging(
config.get_section(_xpath("logging"), default=None) or Configuration()
)
config = Configuration.resolve(env_vars, defaults or {}, _is_root_config=True)
_configure_logging(config)
return config
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

from dataclasses import dataclass
from typing import Mapping
from typing_extensions import Self

from microsoft_agents.activity.errors import configuration_errors

from ..configuration import Configuration, _Configurable
from ..configuration import Configuration, _RootConfigurable
from .._utils import _xpath
from ._constants import _NAME_TO_LEVEL

Expand All @@ -35,13 +36,19 @@ def __init__(self, namespace: str, level: str) -> None:


@dataclass(frozen=True)
class _LoggingConfiguration(_Configurable):
class _LoggingConfiguration(_RootConfigurable):
"""Configuration class for logging levels."""

log_levels: list[_LogLevelEntry]

@classmethod
def _from_configuration(cls, config: Configuration) -> _LoggingConfiguration:
def _from_root_configuration(cls, config: Configuration) -> _LoggingConfiguration:
return cls._from_scoped_configuration(
config.get_section(_xpath("logging"), default=Configuration())
)

@classmethod
def _from_scoped_configuration(cls, config: Configuration) -> _LoggingConfiguration:

raw_log_levels = config.get(_xpath("log_level"), default={})
if not isinstance(raw_log_levels, Mapping):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from abc import ABC, abstractmethod
from typing import (
Any,
Callable,
Iterable,
Mapping,
TypeVar,
Expand Down Expand Up @@ -50,19 +49,30 @@ class Configuration(dict, _ConfigurationProtocol):
"""

def __init__(
self, _original: Mapping | None = None, _base_path: str | None = None, **kwargs
self,
original: Mapping | None = None,
_base_path: str | None = None,
_is_root_config: bool | None = None,
**kwargs,
):
"""Initialize a Configuration instance.

:param _original: The original mapping to initialize the configuration from.
:param original: The original mapping to initialize the configuration from.
:param _base_path: The base path for resolving nested configuration keys.
"""
if _original is not None and kwargs:
raise ValueError("Cannot provide both '_original' and keyword arguments.")
super().__init__(_original or kwargs)
if original is not None and kwargs:
raise ValueError("Cannot provide both 'original' and keyword arguments.")
super().__init__(original or kwargs)
self._base_path = _base_path or ""
if isinstance(original, Configuration) and _is_root_config is None:
_is_root_config = original._is_root_config
self._is_root_config = _is_root_config or False
self._key = None

@property
def is_root_config(self) -> bool:
return self._is_root_config

@property
def base_path(self) -> str:
return self._base_path
Expand All @@ -77,9 +87,27 @@ def key(self) -> str:
)
return self._key

@classmethod
def resolve(
cls,
primary: Mapping | None = None,
defaults: Mapping | None = None,
*,
_base_path: str | None = None,
_is_root_config: bool | None = None,
) -> Configuration:
resolved = _resolve(primary or {}, defaults or {})
return Configuration(
resolved, _base_path=_base_path, _is_root_config=_is_root_config
)

@classmethod
def from_mapping(
cls, _mapping: Mapping | None = None, _base_path: str | None = None, **kwargs
cls,
_mapping: Mapping | None = None,
_base_path: str | None = None,
_is_root_config: bool | None = None,
**kwargs,
) -> Configuration:
"""Create configuration, using keyword arguments as fallback values.

Expand All @@ -90,6 +118,7 @@ def from_mapping(
isinstance(_mapping, Configuration)
and not kwargs
and (_base_path is None or _base_path == _mapping._base_path)
and (_is_root_config is None or _is_root_config == _mapping._is_root_config)
):
return _mapping
if kwargs:
Expand All @@ -99,16 +128,23 @@ def from_mapping(
resolved = _resolve(_mapping, kwargs, path_transformer=lambda x: x)
else:
resolved = _mapping
return cls(resolved, _base_path=_base_path)

if _is_root_config is None:
if isinstance(_mapping, Configuration):
_is_root_config = _mapping._is_root_config
return cls(resolved, _base_path=_base_path, _is_root_config=_is_root_config)

@classmethod
def from_config(self, base: Configuration | None, **kwargs) -> Configuration:
def from_config(cls, base: Configuration | None, **kwargs) -> Configuration:
"""Create a new Configuration instance by forking the current configuration with additional key-value pairs."""
if base is None:
return Configuration(**kwargs)
return Configuration(**kwargs, _is_root_config=False)
new_config = base.copy()
return Configuration.from_mapping(
new_config, _base_path=base._base_path, **kwargs
new_config,
_base_path=base._base_path,
_is_root_config=base._is_root_config,
**kwargs,
)

def _resolve_path(self, key: str) -> str:
Expand Down Expand Up @@ -439,9 +475,28 @@ def from_mapping(cls, _mapping: Mapping | None = None, **kwargs) -> Self:
def _from_configuration(cls, config: Configuration) -> Self: ...

@classmethod
def from_configuration(cls, config: Configuration | Self) -> Self:
def from_configuration(cls, config: Configuration | Self | None) -> Self:
if config is None:
config = Configuration()
if isinstance(config, cls):
return config
if isinstance(config, Configuration):
return cls._from_configuration(config)
raise TypeError(f"Cannot create {cls.__name__} from {type(config).__name__}")


class _RootConfigurable(_Configurable, ABC):

@classmethod
def _from_configuration(cls, config: Configuration) -> Self:
if config._is_root_config:
return cls._from_root_configuration(config)
return cls._from_scoped_configuration(config)

@classmethod
@abstractmethod
def _from_scoped_configuration(cls, config: Configuration) -> Self: ...

@classmethod
@abstractmethod
def _from_root_configuration(cls, config: Configuration) -> Self: ...
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import jwt
import warnings

from typing import Any
from urllib.parse import urlparse, ParseResult as URI
from msal import (
ConfidentialClientApplication,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from .app.oauth import (
Authorization,
AuthHandler,
AuthHandlerSettings,
AgenticUserAuthorization,
)

Expand Down Expand Up @@ -156,6 +157,7 @@
"TempState",
"Authorization",
"AuthHandler",
"AuthHandlerSettings",
"AccessTokenProviderBase",
"AuthenticationConstants",
"AnonymousTokenProvider",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .oauth import (
Authorization,
AuthHandler,
AuthHandlerSettings,
AgenticUserAuthorization,
)

Expand All @@ -44,7 +45,6 @@
"InputFile",
"InputFileDownloader",
"Query",
"Route",
"RouteRank",
"RouteHandler",
"TypingChannelStrategy",
Expand All @@ -58,9 +58,10 @@
"TurnState",
"TempState",
"Authorization",
"AuthHandler",
"AuthHandlerSettings",
"AgenticUserAuthorization",
# Proactive
"AuthHandler",
"Conversation",
"ConversationBuilder",
"ConversationReferenceBuilder",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
from dataclasses import dataclass, field
from typing import Callable, Optional

from microsoft_agents.hosting.core.app.oauth import AuthHandler
from microsoft_agents.hosting.core.authorization import Connections
from microsoft_agents.hosting.core.app.oauth import AuthHandlerSettings
from microsoft_agents.hosting.core.storage import Storage

# from .auth import AuthOptions
Expand Down Expand Up @@ -81,7 +80,7 @@ class ApplicationOptions:
If not provided, the default `TurnState` will be used.
"""

authorization_handlers: Optional[dict[str, AuthHandler]] = None
authorization_handlers: Optional[dict[str, AuthHandlerSettings]] = None
"""
Optional. Authorization handler for OAuth flows.
If not provided, no OAuth flows will be supported.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


from .authorization import Authorization
from .auth_handler import AuthHandler
from .auth_handler import AuthHandler, AuthHandlerSettings
from ._sign_in_state import _SignInState
from ._sign_in_response import _SignInResponse
from ._handlers import (
Expand All @@ -16,6 +16,7 @@
__all__ = [
"Authorization",
"AuthHandler",
"AuthHandlerSettings",
"_AuthorizationHandler",
"_SignInState",
"_SignInResponse",
Expand Down
Loading
Loading