Add YAPF style + ignore, and format tracked Python files
This commit is contained in:
237
result_table.py
237
result_table.py
@@ -41,7 +41,11 @@ def _sanitize_cell_text(value: Any) -> str:
|
||||
text = str(value)
|
||||
if not text:
|
||||
return ""
|
||||
return text.replace("\r\n", " ").replace("\n", " ").replace("\r", " ").replace("\t", " ")
|
||||
return text.replace("\r\n",
|
||||
" ").replace("\n",
|
||||
" ").replace("\r",
|
||||
" ").replace("\t",
|
||||
" ")
|
||||
|
||||
|
||||
def _format_duration_hms(duration: Any) -> str:
|
||||
@@ -130,7 +134,11 @@ def _as_dict(item: Any) -> Optional[Dict[str, Any]]:
|
||||
def extract_store_value(item: Any) -> str:
|
||||
data = _as_dict(item) or {}
|
||||
store = _get_first_dict_value(
|
||||
data, ["store", "table", "source", "storage"]
|
||||
data,
|
||||
["store",
|
||||
"table",
|
||||
"source",
|
||||
"storage"]
|
||||
) # storage is legacy
|
||||
return str(store or "").strip()
|
||||
|
||||
@@ -145,19 +153,33 @@ def extract_title_value(item: Any) -> str:
|
||||
data = _as_dict(item) or {}
|
||||
title = _get_first_dict_value(data, ["title", "name", "filename"])
|
||||
if not title:
|
||||
title = _get_first_dict_value(data, ["target", "path", "url"]) # last resort display
|
||||
title = _get_first_dict_value(
|
||||
data,
|
||||
["target",
|
||||
"path",
|
||||
"url"]
|
||||
) # last resort display
|
||||
return str(title or "").strip()
|
||||
|
||||
|
||||
def extract_ext_value(item: Any) -> str:
|
||||
data = _as_dict(item) or {}
|
||||
|
||||
meta = data.get("metadata") if isinstance(data.get("metadata"), dict) else {}
|
||||
raw_path = data.get("path") or data.get("target") or data.get("filename") or data.get("title")
|
||||
meta = data.get("metadata") if isinstance(data.get("metadata"),
|
||||
dict) else {}
|
||||
raw_path = data.get("path") or data.get("target") or data.get(
|
||||
"filename"
|
||||
) or data.get("title")
|
||||
|
||||
ext = _get_first_dict_value(data, ["ext", "file_ext", "extension"]) or _get_first_dict_value(
|
||||
meta, ["ext", "file_ext", "extension"]
|
||||
)
|
||||
ext = _get_first_dict_value(data,
|
||||
["ext",
|
||||
"file_ext",
|
||||
"extension"]) or _get_first_dict_value(
|
||||
meta,
|
||||
["ext",
|
||||
"file_ext",
|
||||
"extension"]
|
||||
)
|
||||
|
||||
if (not ext) and raw_path:
|
||||
try:
|
||||
@@ -177,11 +199,24 @@ def extract_ext_value(item: Any) -> str:
|
||||
|
||||
def extract_size_bytes_value(item: Any) -> Optional[int]:
|
||||
data = _as_dict(item) or {}
|
||||
meta = data.get("metadata") if isinstance(data.get("metadata"), dict) else {}
|
||||
meta = data.get("metadata") if isinstance(data.get("metadata"),
|
||||
dict) else {}
|
||||
|
||||
size_val = _get_first_dict_value(
|
||||
data, ["size_bytes", "size", "file_size", "bytes", "filesize"]
|
||||
) or _get_first_dict_value(meta, ["size_bytes", "size", "file_size", "bytes", "filesize"])
|
||||
data,
|
||||
["size_bytes",
|
||||
"size",
|
||||
"file_size",
|
||||
"bytes",
|
||||
"filesize"]
|
||||
) or _get_first_dict_value(
|
||||
meta,
|
||||
["size_bytes",
|
||||
"size",
|
||||
"file_size",
|
||||
"bytes",
|
||||
"filesize"]
|
||||
)
|
||||
if size_val is None:
|
||||
return None
|
||||
try:
|
||||
@@ -194,18 +229,30 @@ def extract_size_bytes_value(item: Any) -> Optional[int]:
|
||||
return None
|
||||
|
||||
|
||||
COMMON_COLUMNS: Dict[str, TableColumn] = {
|
||||
"title": TableColumn("title", "Title", extract_title_value),
|
||||
"store": TableColumn("store", "Store", extract_store_value),
|
||||
"hash": TableColumn("hash", "Hash", extract_hash_value),
|
||||
"ext": TableColumn("ext", "Ext", extract_ext_value),
|
||||
"size": TableColumn("size", "Size", extract_size_bytes_value),
|
||||
}
|
||||
COMMON_COLUMNS: Dict[str,
|
||||
TableColumn] = {
|
||||
"title": TableColumn("title",
|
||||
"Title",
|
||||
extract_title_value),
|
||||
"store": TableColumn("store",
|
||||
"Store",
|
||||
extract_store_value),
|
||||
"hash": TableColumn("hash",
|
||||
"Hash",
|
||||
extract_hash_value),
|
||||
"ext": TableColumn("ext",
|
||||
"Ext",
|
||||
extract_ext_value),
|
||||
"size": TableColumn("size",
|
||||
"Size",
|
||||
extract_size_bytes_value),
|
||||
}
|
||||
|
||||
|
||||
def build_display_row(item: Any, *, keys: List[str]) -> Dict[str, Any]:
|
||||
"""Build a dict suitable for `ResultTable.add_result()` using shared column specs."""
|
||||
out: Dict[str, Any] = {}
|
||||
out: Dict[str,
|
||||
Any] = {}
|
||||
for k in keys:
|
||||
spec = COMMON_COLUMNS.get(k)
|
||||
if spec is None:
|
||||
@@ -299,7 +346,10 @@ class ResultColumn:
|
||||
|
||||
def to_dict(self) -> Dict[str, str]:
|
||||
"""Convert to dictionary."""
|
||||
return {"name": self.name, "value": self.value}
|
||||
return {
|
||||
"name": self.name,
|
||||
"value": self.value
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -397,8 +447,8 @@ class ResultTable:
|
||||
try:
|
||||
cmdlet_name = (
|
||||
ctx.get_current_cmdlet_name("")
|
||||
if hasattr(ctx, "get_current_cmdlet_name")
|
||||
else ""
|
||||
if hasattr(ctx,
|
||||
"get_current_cmdlet_name") else ""
|
||||
)
|
||||
except Exception:
|
||||
cmdlet_name = ""
|
||||
@@ -406,7 +456,9 @@ class ResultTable:
|
||||
stage_text = ""
|
||||
try:
|
||||
stage_text = (
|
||||
ctx.get_current_stage_text("") if hasattr(ctx, "get_current_stage_text") else ""
|
||||
ctx.get_current_stage_text("")
|
||||
if hasattr(ctx,
|
||||
"get_current_stage_text") else ""
|
||||
)
|
||||
except Exception:
|
||||
stage_text = ""
|
||||
@@ -415,10 +467,11 @@ class ResultTable:
|
||||
normalized_cmd = str(cmdlet_name).replace("_", "-").strip().lower()
|
||||
normalized_title = str(self.title or "").strip().lower()
|
||||
normalized_stage = str(stage_text).strip()
|
||||
if normalized_stage and normalized_stage.lower().startswith(normalized_cmd):
|
||||
if (not normalized_title) or normalized_title.replace("_", "-").startswith(
|
||||
normalized_cmd
|
||||
):
|
||||
if normalized_stage and normalized_stage.lower().startswith(
|
||||
normalized_cmd):
|
||||
if (not normalized_title) or normalized_title.replace(
|
||||
"_",
|
||||
"-").startswith(normalized_cmd):
|
||||
self.title = normalized_stage
|
||||
except Exception:
|
||||
pass
|
||||
@@ -427,8 +480,10 @@ class ResultTable:
|
||||
max_columns if max_columns is not None else 5
|
||||
) # Default 5 for cleaner display
|
||||
self.rows: List[ResultRow] = []
|
||||
self.column_widths: Dict[str, int] = {}
|
||||
self.input_options: Dict[str, InputOption] = {}
|
||||
self.column_widths: Dict[str,
|
||||
int] = {}
|
||||
self.input_options: Dict[str,
|
||||
InputOption] = {}
|
||||
"""Options available for user input (cmdlet arguments)"""
|
||||
self.source_command: Optional[str] = None
|
||||
"""Command that generated this table (e.g., 'download-file URL')"""
|
||||
@@ -449,7 +504,9 @@ class ResultTable:
|
||||
def set_value_case(self, value_case: str) -> "ResultTable":
|
||||
"""Configure display-only casing for rendered cell values."""
|
||||
case = str(value_case or "").strip().lower()
|
||||
if case not in {"lower", "upper", "preserve"}:
|
||||
if case not in {"lower",
|
||||
"upper",
|
||||
"preserve"}:
|
||||
case = "lower"
|
||||
self.value_case = case
|
||||
return self
|
||||
@@ -485,7 +542,11 @@ class ResultTable:
|
||||
self.rows.append(row)
|
||||
return row
|
||||
|
||||
def set_source_command(self, command: str, args: Optional[List[str]] = None) -> "ResultTable":
|
||||
def set_source_command(
|
||||
self,
|
||||
command: str,
|
||||
args: Optional[List[str]] = None
|
||||
) -> "ResultTable":
|
||||
"""Set the source command that generated this table.
|
||||
|
||||
This is used for @N expansion: when user runs @2 | next-cmd, it will expand to:
|
||||
@@ -578,7 +639,8 @@ class ResultTable:
|
||||
|
||||
def set_storage_summary(
|
||||
self,
|
||||
storage_counts: Dict[str, int],
|
||||
storage_counts: Dict[str,
|
||||
int],
|
||||
filter_text: Optional[str] = None,
|
||||
inline: bool = False,
|
||||
) -> str:
|
||||
@@ -633,7 +695,8 @@ class ResultTable:
|
||||
# Sort rows by the title column value (case-insensitive)
|
||||
self.rows.sort(
|
||||
key=lambda row: (
|
||||
row.columns[title_col_idx].value.lower() if title_col_idx < len(row.columns) else ""
|
||||
row.columns[title_col_idx].value.lower()
|
||||
if title_col_idx < len(row.columns) else ""
|
||||
)
|
||||
)
|
||||
|
||||
@@ -657,7 +720,8 @@ class ResultTable:
|
||||
elif hasattr(result, "__class__") and result.__class__.__name__ == "ResultItem":
|
||||
self._add_result_item(row, result)
|
||||
# Handle SearchResult from search_file.py
|
||||
elif hasattr(result, "__class__") and result.__class__.__name__ == "SearchResult":
|
||||
elif hasattr(result,
|
||||
"__class__") and result.__class__.__name__ == "SearchResult":
|
||||
self._add_search_result(row, result)
|
||||
# Handle PipeObject from models.py
|
||||
elif hasattr(result, "__class__") and result.__class__.__name__ == "PipeObject":
|
||||
@@ -741,7 +805,11 @@ class ResultTable:
|
||||
"""
|
||||
# Title (required)
|
||||
title = getattr(item, "title", None) or "Unknown"
|
||||
table = str(getattr(item, "table", "") or getattr(item, "store", "") or "").lower()
|
||||
table = str(getattr(item,
|
||||
"table",
|
||||
"") or getattr(item,
|
||||
"store",
|
||||
"") or "").lower()
|
||||
|
||||
# Handle extension separation for local files
|
||||
extension = ""
|
||||
@@ -859,18 +927,17 @@ class ResultTable:
|
||||
return False
|
||||
|
||||
# Strip out hidden metadata fields (prefixed with __)
|
||||
visible_data = {k: v for k, v in data.items() if not is_hidden_field(k)}
|
||||
visible_data = {
|
||||
k: v
|
||||
for k, v in data.items() if not is_hidden_field(k)
|
||||
}
|
||||
|
||||
# Normalize common fields using shared extractors so nested metadata/path values work.
|
||||
# This keeps Ext/Size/Store consistent across all dict-based result sources.
|
||||
try:
|
||||
store_extracted = extract_store_value(data)
|
||||
if (
|
||||
store_extracted
|
||||
and "store" not in visible_data
|
||||
and "table" not in visible_data
|
||||
and "source" not in visible_data
|
||||
):
|
||||
if (store_extracted and "store" not in visible_data
|
||||
and "table" not in visible_data and "source" not in visible_data):
|
||||
visible_data["store"] = store_extracted
|
||||
except Exception:
|
||||
pass
|
||||
@@ -884,20 +951,19 @@ class ResultTable:
|
||||
|
||||
try:
|
||||
size_extracted = extract_size_bytes_value(data)
|
||||
if (
|
||||
size_extracted is not None
|
||||
and "size_bytes" not in visible_data
|
||||
and "size" not in visible_data
|
||||
):
|
||||
if (size_extracted is not None and "size_bytes" not in visible_data
|
||||
and "size" not in visible_data):
|
||||
visible_data["size_bytes"] = size_extracted
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Handle extension separation for local files
|
||||
store_val = str(
|
||||
visible_data.get("store", "")
|
||||
or visible_data.get("table", "")
|
||||
or visible_data.get("source", "")
|
||||
visible_data.get("store",
|
||||
"") or visible_data.get("table",
|
||||
"")
|
||||
or visible_data.get("source",
|
||||
"")
|
||||
).lower()
|
||||
|
||||
# Debug logging
|
||||
@@ -906,7 +972,8 @@ class ResultTable:
|
||||
if store_val == "local":
|
||||
# Find title field
|
||||
title_field = next(
|
||||
(f for f in ["title", "name", "filename"] if f in visible_data), None
|
||||
(f for f in ["title", "name", "filename"] if f in visible_data),
|
||||
None
|
||||
)
|
||||
if title_field:
|
||||
title_val = str(visible_data[title_field])
|
||||
@@ -938,11 +1005,8 @@ class ResultTable:
|
||||
|
||||
# Special handling for 'columns' field from search providers
|
||||
# If present, use it to populate row columns dynamically
|
||||
if (
|
||||
"columns" in visible_data
|
||||
and isinstance(visible_data["columns"], list)
|
||||
and visible_data["columns"]
|
||||
):
|
||||
if ("columns" in visible_data and isinstance(visible_data["columns"],
|
||||
list) and visible_data["columns"]):
|
||||
try:
|
||||
for col_name, col_value in visible_data["columns"]:
|
||||
# Skip the "#" column as ResultTable already adds row numbers
|
||||
@@ -956,10 +1020,14 @@ class ResultTable:
|
||||
if col_value is None or str(col_value).strip() == "":
|
||||
col_value_str = ""
|
||||
else:
|
||||
col_value_str = _format_size(col_value, integer_only=False)
|
||||
col_value_str = _format_size(
|
||||
col_value,
|
||||
integer_only=False
|
||||
)
|
||||
except Exception:
|
||||
col_value_str = format_value(col_value)
|
||||
elif isinstance(col_name, str) and col_name.strip().lower() == "duration":
|
||||
elif isinstance(col_name,
|
||||
str) and col_name.strip().lower() == "duration":
|
||||
try:
|
||||
if col_value is None or str(col_value).strip() == "":
|
||||
col_value_str = ""
|
||||
@@ -984,7 +1052,9 @@ class ResultTable:
|
||||
added_fields.add("media_kind")
|
||||
added_fields.add("detail")
|
||||
added_fields.add("annotations")
|
||||
added_fields.add("full_metadata") # Don't display full metadata as column
|
||||
added_fields.add(
|
||||
"full_metadata"
|
||||
) # Don't display full metadata as column
|
||||
except Exception:
|
||||
# Fall back to regular field handling if columns format is unexpected
|
||||
pass
|
||||
@@ -993,10 +1063,19 @@ class ResultTable:
|
||||
if column_count == 0:
|
||||
# Explicitly set which columns to display in order
|
||||
priority_groups = [
|
||||
("title", ["title", "name", "filename"]),
|
||||
("store", ["store", "table", "source"]),
|
||||
("size", ["size", "size_bytes"]),
|
||||
("ext", ["ext"]),
|
||||
("title",
|
||||
["title",
|
||||
"name",
|
||||
"filename"]),
|
||||
("store",
|
||||
["store",
|
||||
"table",
|
||||
"source"]),
|
||||
("size",
|
||||
["size",
|
||||
"size_bytes"]),
|
||||
("ext",
|
||||
["ext"]),
|
||||
]
|
||||
|
||||
# Add priority field groups first - use first match in each group
|
||||
@@ -1007,7 +1086,10 @@ class ResultTable:
|
||||
if field in visible_data and field not in added_fields:
|
||||
# Special handling for size fields - format with unit and decimals
|
||||
if field in ["size", "size_bytes"]:
|
||||
value_str = _format_size(visible_data[field], integer_only=False)
|
||||
value_str = _format_size(
|
||||
visible_data[field],
|
||||
integer_only=False
|
||||
)
|
||||
else:
|
||||
value_str = format_value(visible_data[field])
|
||||
|
||||
@@ -1070,7 +1152,11 @@ class ResultTable:
|
||||
table.add_column("#", justify="right", no_wrap=True)
|
||||
|
||||
# Render headers in uppercase, but keep original column keys for lookup.
|
||||
header_by_key: Dict[str, str] = {name: str(name).upper() for name in col_names}
|
||||
header_by_key: Dict[str,
|
||||
str] = {
|
||||
name: str(name).upper()
|
||||
for name in col_names
|
||||
}
|
||||
|
||||
for name in col_names:
|
||||
header = header_by_key.get(name, str(name).upper())
|
||||
@@ -1132,7 +1218,10 @@ class ResultTable:
|
||||
Returns:
|
||||
Dictionary representation
|
||||
"""
|
||||
return {"title": self.title, "rows": [row.to_list() for row in self.rows]}
|
||||
return {
|
||||
"title": self.title,
|
||||
"rows": [row.to_list() for row in self.rows]
|
||||
}
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""String representation.
|
||||
@@ -1163,7 +1252,9 @@ class ResultTable:
|
||||
return self.rows[index]
|
||||
|
||||
def select_interactive(
|
||||
self, prompt: str = "Select an item", accept_args: bool = False
|
||||
self,
|
||||
prompt: str = "Select an item",
|
||||
accept_args: bool = False
|
||||
) -> Optional[List[int]] | dict:
|
||||
"""Display table and get interactive user selection (single or multiple).
|
||||
|
||||
@@ -1294,7 +1385,8 @@ class ResultTable:
|
||||
end = int(range_parts[1].strip())
|
||||
|
||||
# Validate range
|
||||
if start < 1 or end < 1 or start > len(self.rows) or end > len(self.rows):
|
||||
if start < 1 or end < 1 or start > len(self.rows) or end > len(
|
||||
self.rows):
|
||||
return None
|
||||
|
||||
if start > end:
|
||||
@@ -1373,7 +1465,10 @@ class ResultTable:
|
||||
else:
|
||||
i += 1
|
||||
|
||||
return {"indices": selected_indices, "args": cmdlet_args}
|
||||
return {
|
||||
"indices": selected_indices,
|
||||
"args": cmdlet_args
|
||||
}
|
||||
|
||||
def add_input_option(self, option: InputOption) -> "ResultTable":
|
||||
"""Add an interactive input option to the table.
|
||||
@@ -1510,7 +1605,9 @@ class ResultTable:
|
||||
rows.append(row_values)
|
||||
return rows
|
||||
|
||||
def _format_datatable_row(self, row: ResultRow, source: str = "unknown") -> List[str]:
|
||||
def _format_datatable_row(self,
|
||||
row: ResultRow,
|
||||
source: str = "unknown") -> List[str]:
|
||||
"""Format a ResultRow for DataTable display.
|
||||
|
||||
Args:
|
||||
|
||||
Reference in New Issue
Block a user