refactor: ленивый резолв приоритетов без замены в репозитории
Изменения: - _resolve_relative_priorities() возвращает словарь вместо замены - Приоритеты не заменяются в ConversionPoint - resolved_priorities передаётся в filter_exploded_callgraph_branch - get_aggregate_priority использует resolved_priorities если есть Преимущества: - Относительные приоритеты сохраняются в репозитории - Можно добавлять новые инжекторы после get_conversion() - Нет мутации состояния репозитория - Каждый вызов get_conversion() использует актуальные приоритеты Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -52,9 +52,9 @@ class ConvRepo:
|
|||||||
allow_sync: bool = True,
|
allow_sync: bool = True,
|
||||||
force_async: bool = False
|
force_async: bool = False
|
||||||
):
|
):
|
||||||
# Разрешаем относительные приоритеты
|
# Разрешаем относительные приоритеты (не заменяя, а получая словарь)
|
||||||
self._resolve_relative_priorities()
|
resolved_priorities = self._resolve_relative_priorities()
|
||||||
|
|
||||||
filtered_injectors = self.filtered_injectors(allow_async, allow_sync)
|
filtered_injectors = self.filtered_injectors(allow_async, allow_sync)
|
||||||
pipeline_callseq = []
|
pipeline_callseq = []
|
||||||
orig_from_types = tuple(from_types)
|
orig_from_types = tuple(from_types)
|
||||||
@@ -71,7 +71,13 @@ class ConvRepo:
|
|||||||
else:
|
else:
|
||||||
injects = extract_return_type(fn)
|
injects = extract_return_type(fn)
|
||||||
|
|
||||||
callseq = self.get_callseq(filtered_injectors, frozenset(from_types), fn, force_commutative)
|
callseq = self.get_callseq(
|
||||||
|
filtered_injectors,
|
||||||
|
frozenset(from_types),
|
||||||
|
fn,
|
||||||
|
force_commutative,
|
||||||
|
resolved_priorities
|
||||||
|
)
|
||||||
|
|
||||||
pipeline_callseq += callseq
|
pipeline_callseq += callseq
|
||||||
|
|
||||||
@@ -133,7 +139,8 @@ class ConvRepo:
|
|||||||
injectors: frozenset[ConversionPoint],
|
injectors: frozenset[ConversionPoint],
|
||||||
from_types: frozenset[type],
|
from_types: frozenset[type],
|
||||||
fn: Callable | Iterable[ConversionPoint] | ConversionPoint,
|
fn: Callable | Iterable[ConversionPoint] | ConversionPoint,
|
||||||
force_commutative: bool) -> list[ConversionPoint]:
|
force_commutative: bool,
|
||||||
|
resolved_priorities: Optional[dict[ConversionPoint, float]] = None) -> list[ConversionPoint]:
|
||||||
|
|
||||||
cg = self.walker.generate_callgraph(injectors, from_types, fn)
|
cg = self.walker.generate_callgraph(injectors, from_types, fn)
|
||||||
if cg is None:
|
if cg is None:
|
||||||
@@ -142,12 +149,12 @@ class ConvRepo:
|
|||||||
for inj in injectors:
|
for inj in injectors:
|
||||||
available_types.add(inj.injects)
|
available_types.add(inj.injects)
|
||||||
available_types.update(inj.requires)
|
available_types.update(inj.requires)
|
||||||
|
|
||||||
# Определяем требуемые типы
|
# Определяем требуемые типы
|
||||||
required_types = set()
|
required_types = set()
|
||||||
if callable(fn):
|
if callable(fn):
|
||||||
required_types = extract_func_argtypes(fn)
|
required_types = extract_func_argtypes(fn)
|
||||||
|
|
||||||
raise NoConversionPath(
|
raise NoConversionPath(
|
||||||
from_types=tuple(from_types),
|
from_types=tuple(from_types),
|
||||||
target=fn,
|
target=fn,
|
||||||
@@ -157,7 +164,11 @@ class ConvRepo:
|
|||||||
|
|
||||||
exploded = self.walker.explode_callgraph_branches(cg, from_types)
|
exploded = self.walker.explode_callgraph_branches(cg, from_types)
|
||||||
|
|
||||||
selected = self.walker.filter_exploded_callgraph_branch(exploded)
|
# Передаём resolved_priorities в filter_exploded_callgraph_branch
|
||||||
|
selected = self.walker.filter_exploded_callgraph_branch(
|
||||||
|
exploded,
|
||||||
|
resolved_priorities=resolved_priorities
|
||||||
|
)
|
||||||
if len(selected) == 0:
|
if len(selected) == 0:
|
||||||
raise NoConversionPath(
|
raise NoConversionPath(
|
||||||
from_types=tuple(from_types),
|
from_types=tuple(from_types),
|
||||||
@@ -222,8 +233,8 @@ class ConvRepo:
|
|||||||
reason="force_async=True requires allow_async=True"
|
reason="force_async=True requires allow_async=True"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Разрешаем относительные приоритеты
|
# Разрешаем относительные приоритеты (не заменяя, а получая словарь)
|
||||||
self._resolve_relative_priorities()
|
resolved_priorities = self._resolve_relative_priorities()
|
||||||
|
|
||||||
filtered_injectors = self.filtered_injectors(allow_async, allow_sync)
|
filtered_injectors = self.filtered_injectors(allow_async, allow_sync)
|
||||||
|
|
||||||
@@ -231,7 +242,8 @@ class ConvRepo:
|
|||||||
filtered_injectors,
|
filtered_injectors,
|
||||||
frozenset(from_types),
|
frozenset(from_types),
|
||||||
fn,
|
fn,
|
||||||
force_commutative
|
force_commutative,
|
||||||
|
resolved_priorities
|
||||||
)
|
)
|
||||||
|
|
||||||
ret_fn = self.renderer.render(from_types, callseq, force_async=force_async, store_sources=self.store_sources)
|
ret_fn = self.renderer.render(from_types, callseq, force_async=force_async, store_sources=self.store_sources)
|
||||||
@@ -253,30 +265,22 @@ class ConvRepo:
|
|||||||
"""
|
"""
|
||||||
Разрешить относительные приоритеты и вычислить абсолютные значения.
|
Разрешить относительные приоритеты и вычислить абсолютные значения.
|
||||||
|
|
||||||
Проходит по всем инжекторам и если есть относительные приоритеты,
|
Не заменяет приоритеты в репозитории, а возвращает словарь
|
||||||
вычисляет абсолютные значения на основе графа зависимостей.
|
{ConversionPoint: float_priority} для использования в graph_walker.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[ConversionPoint, float] или None если нет относительных приоритетов
|
||||||
"""
|
"""
|
||||||
injectors = list(self.convertor_set)
|
injectors = list(self.convertor_set)
|
||||||
|
|
||||||
# Проверяем есть ли относительные приоритеты
|
# Проверяем есть ли относительные приоритеты
|
||||||
has_relative = any(isinstance(cp.priority, RelativePriority) for cp in injectors)
|
has_relative = any(isinstance(cp.priority, RelativePriority) for cp in injectors)
|
||||||
if not has_relative:
|
if not has_relative:
|
||||||
return
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
priorities = resolve_priorities(injectors)
|
priorities = resolve_priorities(injectors)
|
||||||
|
return priorities
|
||||||
# Применяем разрешённые приоритеты
|
|
||||||
# Создаём новые ConversionPoint с абсолютными приоритетами
|
|
||||||
new_injectors = set()
|
|
||||||
for cp in injectors:
|
|
||||||
if cp in priorities:
|
|
||||||
new_injectors.add(cp.copy_with(priority=priorities[cp]))
|
|
||||||
else:
|
|
||||||
new_injectors.add(cp)
|
|
||||||
|
|
||||||
# Обновляем репозиторий
|
|
||||||
self._convertor_set = new_injectors
|
|
||||||
|
|
||||||
except CycleDetectedError as e:
|
except CycleDetectedError as e:
|
||||||
# Переупаковываем в наше исключение
|
# Переупаковываем в наше исключение
|
||||||
|
|||||||
@@ -134,7 +134,8 @@ class GraphWalker:
|
|||||||
def filter_exploded_callgraph_branch(cls,
|
def filter_exploded_callgraph_branch(cls,
|
||||||
variants: list[CallgraphVariant],
|
variants: list[CallgraphVariant],
|
||||||
priority_injectors: Optional[frozenset[ConversionPoint | Callable]] = None,
|
priority_injectors: Optional[frozenset[ConversionPoint | Callable]] = None,
|
||||||
relevance_metric: Optional[Callable[[CallgraphVariant], int | float]] = None) \
|
relevance_metric: Optional[Callable[[CallgraphVariant], int | float]] = None,
|
||||||
|
resolved_priorities: Optional[dict[ConversionPoint, float]] = None) \
|
||||||
-> list[CallgraphVariant]:
|
-> list[CallgraphVariant]:
|
||||||
|
|
||||||
if relevance_metric is None:
|
if relevance_metric is None:
|
||||||
@@ -148,7 +149,7 @@ class GraphWalker:
|
|||||||
for metric in template_metrics:
|
for metric in template_metrics:
|
||||||
if len(variants) == 1:
|
if len(variants) == 1:
|
||||||
break
|
break
|
||||||
new_variants = cls.filter_exploded_callgraph_branch(variants, priority_injectors, metric)
|
new_variants = cls.filter_exploded_callgraph_branch(variants, priority_injectors, metric, resolved_priorities)
|
||||||
if len(new_variants) > 0:
|
if len(new_variants) > 0:
|
||||||
variants = new_variants
|
variants = new_variants
|
||||||
|
|
||||||
@@ -156,21 +157,26 @@ class GraphWalker:
|
|||||||
if len(variants) > 1:
|
if len(variants) > 1:
|
||||||
# Вычисляем aggregate priority для каждого варианта (сумма приоритетов всех инжекторов в пути)
|
# Вычисляем aggregate priority для каждого варианта (сумма приоритетов всех инжекторов в пути)
|
||||||
def get_aggregate_priority(variant: CallgraphVariant) -> float:
|
def get_aggregate_priority(variant: CallgraphVariant) -> float:
|
||||||
priority = variant.injector.priority
|
# Используем resolved_priorities если есть, иначе берём из cp.priority
|
||||||
|
if resolved_priorities and variant.injector in resolved_priorities:
|
||||||
|
priority = resolved_priorities[variant.injector]
|
||||||
|
else:
|
||||||
|
priority = variant.injector.priority if isinstance(variant.injector.priority, (int, float)) else 0.0
|
||||||
|
|
||||||
for subg in variant.subgraphs:
|
for subg in variant.subgraphs:
|
||||||
for subv in subg.variants:
|
for subv in subg.variants:
|
||||||
priority += get_aggregate_priority(subv)
|
priority += get_aggregate_priority(subv)
|
||||||
return priority
|
return priority
|
||||||
|
|
||||||
# Сортировка по aggregate priority (обратный порядок - выше приоритет = раньше)
|
# Сортировка по aggregate priority (обратный порядок - выше приоритет = раньше)
|
||||||
# Затем по имени функции для детерминизма
|
# Затем по имени функции для детерминизма
|
||||||
variants.sort(key=lambda x: (-get_aggregate_priority(x), universal_qualname(x.injector.fn)))
|
variants.sort(key=lambda x: (-get_aggregate_priority(x), universal_qualname(x.injector.fn)))
|
||||||
|
|
||||||
# Выбираем вариант с наивысшим aggregate приоритетом
|
# Выбираем вариант с наивысшим aggregate приоритетом
|
||||||
max_priority = get_aggregate_priority(variants[0])
|
max_priority = get_aggregate_priority(variants[0])
|
||||||
selected = [v for v in variants if get_aggregate_priority(v) == max_priority]
|
selected = [v for v in variants if get_aggregate_priority(v) == max_priority]
|
||||||
variants = selected
|
variants = selected
|
||||||
|
|
||||||
return variants
|
return variants
|
||||||
|
|
||||||
if len(variants) < 2:
|
if len(variants) < 2:
|
||||||
|
|||||||
4
uv.lock
generated
4
uv.lock
generated
@@ -1,10 +1,10 @@
|
|||||||
version = 1
|
version = 1
|
||||||
revision = 2
|
revision = 3
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "breakshaft"
|
name = "breakshaft"
|
||||||
version = "0.1.0.post2"
|
version = "0.1.6.post5"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "hatchling" },
|
{ name = "hatchling" },
|
||||||
|
|||||||
Reference in New Issue
Block a user