"""Absfuyu: Beautiful------------------A decorator that makes output more beautifulVersion: 5.1.0Date updated: 10/03/2025 (dd/mm/yyyy)"""# Module level# ---------------------------------------------------------------------------__all__=["BeautifulOutput","print",]# Library# ---------------------------------------------------------------------------importtimeimporttracemallocfromcollections.abcimportCallablefromfunctoolsimportwrapsfromtypingimportAny,Literal,NamedTuple,ParamSpec,TypeVarBEAUTIFUL_MODE=Falsetry:fromrich.alignimportAlignfromrich.consoleimportConsole,Groupfromrich.panelimportPanelfromrich.tableimportTablefromrich.textimportTextexceptImportError:fromsubprocessimportrunfromabsfuyu.configimportABSFUYU_CONFIGifABSFUYU_CONFIG._get_setting("auto-install-extra").value:cmd="python -m pip install -U absfuyu[beautiful]".split()run(cmd)else:raiseSystemExit("This feature is in absfuyu[beautiful] package")# noqa: B904else:BEAUTIFUL_MODE=True# Setup# ---------------------------------------------------------------------------# rich's console.print wrapperconsole=Console(color_system="auto",tab_size=4)print=console.print# Type# ---------------------------------------------------------------------------P=ParamSpec("P")# Parameter typeR=TypeVar("R")# Return type - Can be anythingT=TypeVar("T",bound=type)# Type type - Can be any subtype of `type`# Class# ---------------------------------------------------------------------------classPerformanceOutput(NamedTuple):runtime:floatcurrent_memory:intpeak_memory:intdefto_text(self)->str:""" Beautify the result and ready to print """out=(f"Memory usage: {self.current_memory/10**6:,.6f} MB\n"f"Peak memory usage: {self.peak_memory/10**6:,.6f} MB\n"f"Time elapsed: {self.runtime:,.6f} s")returnout# TODO: header and footer layout to 1,2,3 instead of true false
[docs]classBeautifulOutput:"""A decorator that makes output more beautiful"""def__init__(self,layout:Literal[1,2,3,4,5,6]=1,include_header:bool=True,include_footer:bool=True,alternate_footer:bool=False,)->None:""" Show function's signature and measure memory usage Parameters ---------- layout : Literal[1, 2, 3, 4, 5, 6], optional Layout to show, by default ``1`` include_header : bool, optional Include header with function's signature, by default ``True`` include_footer : bool, optional Include footer, by default ``True`` alternate_footer : bool, optional Alternative style of footer, by default ``False`` Usage ----- Use this as a decorator (``@BeautifulOutput(<parameters>)``) """self.layout=layoutself.include_header=include_headerself.include_footer=include_footerself.alternate_footer=alternate_footer# Dataself._obj_name=""self._signature=""self._result:Any|None=Noneself._performance:PerformanceOutput|None=None# Settingself._header_footer_style="white on blue"self._alignment="center"def__call__(self,obj:Callable[P,R])->Callable[P,Group]:# Class wrapperifisinstance(obj,type):raiseNotImplementedError("Classes are not supported")# Function wrapper@wraps(obj)defwrapper(*args:P.args,**kwargs:P.kwargs)->Group:""" Wrapper function that executes the original function. """# Get all parameters inputedargs_repr=[repr(a)forainargs]kwargs_repr=[f"{k}={repr(v)}"fork,vinkwargs.items()]self._signature=", ".join(args_repr+kwargs_repr)self._obj_name=obj.__name__# Performance checktracemalloc.start()# Start memory measurestart_time=time.perf_counter()# Start time measureself._result=obj(*args,**kwargs)# Function runfinish_time=time.perf_counter()# Get finished time_cur,_peak=tracemalloc.get_traced_memory()# Get memory statstracemalloc.stop()# End memory measureself._performance=PerformanceOutput(runtime=finish_time-start_time,current_memory=_cur,peak_memory=_peak)returnself._get_layout(layout=self.layout)returnwrapper# Signaturedef_func_signature(self)->str:"""Function's signature"""returnf"{self._obj_name}({self._signature})"# Layoutdef_make_header(self)->Table:header_table=Table.grid(expand=True)header_table.add_row(Panel(Align(f"[b]{self._func_signature()}",align=self._alignment),style=self._header_footer_style,))returnheader_tabledef_make_line(self)->Table:line=Table.grid(expand=True)line.add_row(Text("",style=self._header_footer_style))returnlinedef_make_footer(self)->Table:ifself.alternate_footer:returnself._make_line()footer_table=Table.grid(expand=True)footer_table.add_row(Panel(Align("[b]BeautifulOutput by absfuyu",align=self._alignment),style=self._header_footer_style,))returnfooter_tabledef_make_result_panel(self)->Panel:result_txt=Text(str(self._result),overflow="fold",no_wrap=False,tab_size=2,)result_panel=Panel(Align(result_txt,align=self._alignment),title="[bold]Result[/]",border_style="green",highlight=True,)returnresult_paneldef_make_performance_panel(self)->Panel:ifself._performanceisnotNone:performance_panel=Panel(Align(self._performance.to_text(),align=self._alignment),title="[bold]Performance[/]",border_style="red",highlight=True,# height=result_panel.height,)returnperformance_panelelse:returnPanel("None",title="[bold]Performance[/]")def_make_output(self)->Table:out_table=Table.grid(expand=True)out_table.add_column(ratio=3)# resultout_table.add_column(ratio=2)# performanceout_table.add_row(self._make_result_panel(),self._make_performance_panel(),)returnout_tabledef_get_layout(self,layout:int)->Group:header=self._make_header()ifself.include_headerelseText()footer=self._make_footer()ifself.include_footerelseText()layouts={1:Group(header,self._make_output(),footer),2:Group(header,self._make_result_panel(),self._make_performance_panel()),3:Group(header,self._make_result_panel(),footer),4:Group(self._make_result_panel(),self._make_performance_panel()),5:Group(self._make_output()),6:Group(header,self._make_result_panel(),self._make_performance_panel(),footer,),}returnlayouts.get(layout,layouts[1])