81 lines
2.7 KiB
Python
81 lines
2.7 KiB
Python
"""Provider registry for ResultTable API (breaking, strict API).
|
|
|
|
Providers register themselves here with an adapter and optional column factory
|
|
and selection function. Consumers (cmdlets) can look up providers by name and
|
|
obtain the columns and selection behavior for building tables and for selection
|
|
args used by subsequent cmdlets.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any, Callable, Dict, Iterable, List, Optional, Union
|
|
|
|
from SYS.result_table_api import ColumnSpec, ProviderAdapter, ResultModel
|
|
|
|
|
|
ColumnFactory = Callable[[Iterable[ResultModel]], List[ColumnSpec]]
|
|
SelectionFn = Callable[[ResultModel], List[str]]
|
|
|
|
|
|
@dataclass
|
|
class Provider:
|
|
name: str
|
|
adapter: ProviderAdapter
|
|
# columns can be a static list or a factory that derives columns from sample rows
|
|
columns: Optional[Union[List[ColumnSpec], ColumnFactory]] = None
|
|
selection_fn: Optional[SelectionFn] = None
|
|
metadata: Optional[Dict[str, Any]] = None
|
|
|
|
def get_columns(self, rows: Optional[Iterable[ResultModel]] = None) -> List[ColumnSpec]:
|
|
if callable(self.columns):
|
|
try:
|
|
rows_list = list(rows) if rows is not None else []
|
|
return list(self.columns(rows_list))
|
|
except Exception:
|
|
# Fall back to a minimal Title column on errors
|
|
return [ColumnSpec("title", "Title", lambda r: r.title)]
|
|
if self.columns is not None:
|
|
return list(self.columns)
|
|
# Default minimal column set
|
|
return [ColumnSpec("title", "Title", lambda r: r.title)]
|
|
|
|
def selection_args(self, row: ResultModel) -> List[str]:
|
|
if callable(self.selection_fn):
|
|
try:
|
|
return list(self.selection_fn(row))
|
|
except Exception:
|
|
return []
|
|
# Default selector: prefer path flag, then title
|
|
if getattr(row, "path", None):
|
|
return ["-path", str(row.path)]
|
|
return ["-title", str(row.title)]
|
|
|
|
|
|
_PROVIDERS: Dict[str, Provider] = {}
|
|
|
|
|
|
def register_provider(
|
|
name: str,
|
|
adapter: ProviderAdapter,
|
|
*,
|
|
columns: Optional[Union[List[ColumnSpec], ColumnFactory]] = None,
|
|
selection_fn: Optional[SelectionFn] = None,
|
|
metadata: Optional[Dict[str, Any]] = None,
|
|
) -> Provider:
|
|
name = str(name or "").strip().lower()
|
|
if not name:
|
|
raise ValueError("provider name required")
|
|
if name in _PROVIDERS:
|
|
raise ValueError(f"provider already registered: {name}")
|
|
p = Provider(name=name, adapter=adapter, columns=columns, selection_fn=selection_fn, metadata=metadata)
|
|
_PROVIDERS[name] = p
|
|
return p
|
|
|
|
|
|
def get_provider(name: str) -> Provider:
|
|
return _PROVIDERS[name.lower()]
|
|
|
|
|
|
def list_providers() -> List[str]:
|
|
return list(_PROVIDERS.keys())
|