huge refactor of plugin system
This commit is contained in:
+72
-1
@@ -13,7 +13,7 @@ Features:
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List, Optional, Callable, Set
|
||||
from typing import Any, Dict, List, Optional, Callable, Set, Tuple
|
||||
from pathlib import Path
|
||||
import json
|
||||
import re
|
||||
@@ -94,6 +94,42 @@ def _partition_detail_tags(tags: Any) -> tuple[List[str], List[str]]:
|
||||
return namespace_tags, freeform_tags
|
||||
|
||||
|
||||
def _extract_namespace_sort_values(tags: Any, namespace: str) -> List[str]:
|
||||
wanted = str(namespace or "").strip().casefold()
|
||||
if not wanted:
|
||||
return []
|
||||
|
||||
values: List[str] = []
|
||||
for tag in _normalize_detail_tags(tags):
|
||||
ns, sep, value = str(tag).partition(":")
|
||||
if not sep:
|
||||
continue
|
||||
if ns.strip().casefold() != wanted:
|
||||
continue
|
||||
clean_value = value.strip()
|
||||
if clean_value:
|
||||
values.append(clean_value)
|
||||
return values
|
||||
|
||||
|
||||
def _namespace_sort_key(tags: Any, namespace: str, *, numeric: bool = False) -> Tuple[int, Any, str]:
|
||||
values = _extract_namespace_sort_values(tags, namespace)
|
||||
if not values:
|
||||
return (1, float("inf") if numeric else "", "")
|
||||
|
||||
primary = values[0]
|
||||
if numeric:
|
||||
match = re.search(r"-?\d+(?:\.\d+)?", primary)
|
||||
if match:
|
||||
try:
|
||||
return (0, float(match.group(0)), primary.casefold())
|
||||
except Exception:
|
||||
pass
|
||||
return (0, float("inf"), primary.casefold())
|
||||
|
||||
return (0, primary.casefold(), primary.casefold())
|
||||
|
||||
|
||||
def _chunk_detail_tags(tags: List[str], columns: int) -> List[List[str]]:
|
||||
column_count = max(1, int(columns or 1))
|
||||
rows: List[List[str]] = []
|
||||
@@ -954,6 +990,41 @@ class Table:
|
||||
|
||||
return self
|
||||
|
||||
def sort_by_tag_namespace(self, namespace: str, *, numeric: bool = False, reverse: bool = False) -> "Table":
|
||||
"""Sort rows by the first value found for a tag namespace.
|
||||
|
||||
Looks first at row payload tag metadata, then falls back to the visible Tag column.
|
||||
When ``numeric`` is True, the first numeric token inside the namespace value is used.
|
||||
"""
|
||||
if getattr(self, "preserve_order", False):
|
||||
return self
|
||||
|
||||
wanted = str(namespace or "").strip()
|
||||
if not wanted:
|
||||
return self
|
||||
|
||||
def _row_tags(row: Row) -> Any:
|
||||
payload = getattr(row, "payload", None)
|
||||
if isinstance(payload, dict):
|
||||
for key in ("tag", "tags", "tag_summary"):
|
||||
value = payload.get(key)
|
||||
if value:
|
||||
return value
|
||||
metadata = payload.get("metadata")
|
||||
if isinstance(metadata, dict):
|
||||
for key in ("tag", "tags", "tag_summary"):
|
||||
value = metadata.get(key)
|
||||
if value:
|
||||
return value
|
||||
tag_column = row.get_column("Tag")
|
||||
return tag_column or []
|
||||
|
||||
self.rows.sort(
|
||||
key=lambda row: _namespace_sort_key(_row_tags(row), wanted, numeric=bool(numeric)),
|
||||
reverse=bool(reverse),
|
||||
)
|
||||
return self
|
||||
|
||||
def add_result(self, result: Any) -> "Table":
|
||||
"""Add a result object (SearchResult, PipeObject, ResultItem, TagItem, or dict) as a row.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user