# smartseeds/ascii_table.py
# (Modulo completo generato)
import re
import textwrap
from datetime import datetime, date
ANSI_RE = re.compile(r"\x1b\[[0-9;]*m")
def strip_ansi(s): return ANSI_RE.sub("", s)
def normalize_date_format(fmt: str) -> str:
mapping = {
"yyyy": "%Y","yy": "%y","mm": "%m","dd": "%d",
"HH": "%H","MM": "%M","SS": "%S",
}
out = fmt
for k,v in mapping.items(): out = out.replace(k,v)
return out
def parse_bool(value):
v=str(value).strip().lower()
if v in ("true","yes","1"): return True
if v in ("false","no","0"): return False
return value
def format_cell(value, coldef):
ctype=coldef.get("type","str")
fmt=coldef.get("format")
if ctype=="str": return str(value)
if ctype=="bool":
v=parse_bool(value)
return "true" if v is True else "false" if v is False else str(value)
if ctype=="int":
try: return str(int(value))
except: return str(value)
if ctype=="float":
try:
f=float(value)
return format(f,fmt) if fmt else f"{f:g}"
except:
return str(value)
if ctype=="date":
try: d=datetime.fromisoformat(str(value)).date()
except: return str(value)
return d.strftime(normalize_date_format(fmt)) if fmt else d.isoformat()
if ctype=="datetime":
try: dt=datetime.fromisoformat(str(value))
except: return str(value)
return dt.strftime(normalize_date_format(fmt)) if fmt else dt.strftime("%Y-%m-%d %H:%M:%S")
return str(value)
def build_tree(paths,sep):
tree={}
for full in paths:
parts=str(full).split(sep)
node=tree
for p in parts: node=node.setdefault(p,{})
return tree
def flatten_tree(tree,level=0,prefix=""):
out=[]
for key in sorted(tree.keys()):
full=prefix+key if prefix=="" else prefix+"/"+key
children=tree[key]
is_leaf=(len(children)==0)
out.append((full,key,level,is_leaf))
out.extend(flatten_tree(children,level+1,full))
return out
def apply_hierarchy(headers,rows):
for idx,h in enumerate(headers):
if "hierarchy" not in h: continue
sep=h["hierarchy"].get("sep","/")
original=[r[idx] for r in rows]
mapvals={r[idx]: r[1:] for r in rows}
tree=build_tree(original,sep)
tri=flatten_tree(tree)
other=len(rows[0])-1
new=[]
for full,label,lvl,is_leaf in tri:
values=mapvals[full] if is_leaf and full in mapvals else [""]*other
new.append([" "*lvl+label]+values)
return new
return rows
def compute_col_widths(names,rows,max_width=120,minw=6,pad=1):
usable=max_width-(len(names)+1)
widths=[]
for i,n in enumerate(names):
m=len(strip_ansi(n))
for r in rows: m=max(m,len(strip_ansi(str(r[i]))))
widths.append(max(m+pad,minw))
total=sum(widths)
if total>usable:
scale=usable/total
widths=[max(minw,int(w*scale)) for w in widths]
return widths
def wrap_row(row,widths):
return [textwrap.wrap(str(c),w) or [""] for c,w in zip(row,widths)]
def merge_wrapped(wrapped):
ml=max(len(col) for col in wrapped)
return [[col[i] if i<len(col) else "" for col in wrapped] for i in range(ml)]
def apply_align(t,w,align):
if align=="right": return t.rjust(w)
if align=="center": return t.center(w)
return t.ljust(w)
def draw_table(headers,rows,max_width=120):
names=[h["name"] for h in headers]
widths=compute_col_widths(names,rows,max_width)
def sep(): return "+"+ "+".join("-"*w for w in widths) +"+"
out=[sep()]
for line in merge_wrapped(wrap_row(names,widths)):
out.append("|"+"|".join(apply_align(txt,w,h.get("align","left"))
for txt,w,h in zip(line,widths,headers))+"|")
out.append(sep())
for row in rows:
for line in merge_wrapped(wrap_row(row,widths)):
out.append("|"+"|".join(apply_align(txt,w,h.get("align","left"))
for txt,w,h in zip(line,widths,headers))+"|")
out.append(sep())
return "\n".join(out)
[docs]
def render_ascii_table(data,max_width=None):
headers=data["headers"]; rows=data["rows"]
if max_width is None: max_width=data.get("max_width",120)
formatted=[[format_cell(c,h) for c,h in zip(r,headers)] for r in rows]
final=apply_hierarchy(headers,formatted)
table=draw_table(headers,final,max_width=max_width)
title=data.get("title")
return title.center(max_width)+"\n"+table if title else table
[docs]
def render_markdown_table(data):
headers=data["headers"]; rows=data["rows"]
names=[h["name"] for h in headers]
out=[]
out.append("| "+ " | ".join(names)+" |")
out.append("| "+ " | ".join("---" for _ in names)+" |")
for r in rows:
vals=[format_cell(c,h) for c,h in zip(r,headers)]
out.append("| "+ " | ".join(vals)+" |")
return "\n".join(out)