Source code for smartseeds.ascii_table


# 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)