Coverage for src/lexigram/features/decorators/_utils.py: 45%
20 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 02:04 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 02:04 +0800
1"""Shared internal utilities for feature-flag decorators.
3Not part of the public API — import from :mod:`lexigram.features.decorators`
4instead.
5"""
7from __future__ import annotations
9from typing import TYPE_CHECKING, Any
11if TYPE_CHECKING:
12 from collections.abc import Callable
14 from lexigram.features.manager.flag_manager import FlagManager
17def _resolve_manager(manager: FlagManager | None) -> FlagManager:
18 """Resolve FlagManager from provided instance, context var, or fallback.
20 Resolution order:
22 1. Explicit *manager* instance.
23 2. Synchronous DI resolution from the ambient container.
24 3. New local manager (uses ``LocalProvider`` by default).
26 Args:
27 manager: Explicit manager instance or ``None``.
29 Returns:
30 A resolved :class:`~lexigram.features.manager.FlagManager`.
31 """
32 if manager is not None:
33 return manager
35 from lexigram.di.resolution.context import current_resolver_var, get_resolver
37 resolver = get_resolver(None) or current_resolver_var.get()
38 if resolver is not None:
39 from contextlib import suppress
41 with suppress(Exception):
42 if hasattr(resolver, "resolve_sync"):
43 from lexigram.features.manager.flag_manager import FlagManager
45 resolved: FlagManager = resolver.resolve_sync(FlagManager)
46 return resolved
48 from lexigram.features.manager.flag_manager import FlagManager
50 return FlagManager()
53def _is_coroutinefunction(fn: Callable[..., Any]) -> bool:
54 """Return True if *fn* is an async function or coroutine function.
56 Args:
57 fn: Any callable.
59 Returns:
60 True when *fn* is a coroutine function.
61 """
62 import asyncio
63 import inspect
65 return asyncio.iscoroutinefunction(fn) or inspect.iscoroutinefunction(fn)