mirror of https://github.com/eyhc1/rendercv.git
178 lines
5.7 KiB
Python
178 lines
5.7 KiB
Python
import time
|
|
from typing import Callable
|
|
|
|
import rich
|
|
import rich.console
|
|
import rich.panel
|
|
import rich.live
|
|
import rich.table
|
|
import rich.text
|
|
import rich.progress
|
|
|
|
|
|
console = rich.console.Console()
|
|
|
|
|
|
def welcome():
|
|
"""Print a welcome message to the terminal."""
|
|
table = rich.table.Table(
|
|
title="\nWelcome to [bold]Render[dodger_blue3]CV[/dodger_blue3][/bold]!",
|
|
title_justify="center",
|
|
)
|
|
|
|
table.add_column("Title", style="magenta")
|
|
table.add_column("Link", style="cyan", justify="right", no_wrap=True)
|
|
|
|
table.add_row("Documentation", "https://sinaatalay.github.io/rendercv/")
|
|
table.add_row("Source code", "https://github.com/sinaatalay/rendercv/")
|
|
table.add_row("Bug reports", "https://github.com/sinaatalay/rendercv/issues/")
|
|
table.add_row("Feature requests", "https://github.com/sinaatalay/rendercv/issues/")
|
|
|
|
console.print(table, justify="center")
|
|
|
|
|
|
def warning(text):
|
|
"""Print a warning message to the terminal."""
|
|
console.print(f"[bold yellow]{text}[/bold yellow]")
|
|
|
|
|
|
def error(text):
|
|
"""Print an error message to the terminal."""
|
|
console.print(f"[bold red]{text}[/bold red]")
|
|
|
|
|
|
def information(text):
|
|
"""Print an information message to the terminal."""
|
|
console.print(f"[bold green]{text}")
|
|
|
|
|
|
def time_the_event_below(event_name: str) -> Callable:
|
|
"""Return a wrapper function that times the wrapped function.
|
|
|
|
A decorator in Python is a syntactic convenience that allows a Python to interpret
|
|
the code below:
|
|
|
|
```python
|
|
@time_the_event_below("My event")
|
|
def my_function():
|
|
pass
|
|
```
|
|
as
|
|
```python
|
|
time_the_event_below("My event")(my_function)()
|
|
```
|
|
which is step by step equivalent to
|
|
|
|
1. Execute `#!python time_the_event_below("My event")` which will return the
|
|
function called `wrapper`.
|
|
2. Execute `#!python wrapper(my_function)`, which will return another function
|
|
called `wrapped_function`, which does some modifications to `my_function.`
|
|
3. Execute `#!python wrapped_function()`
|
|
"""
|
|
|
|
def wrapper(function: Callable) -> Callable:
|
|
def wrapped_function(*args, **kwargs):
|
|
start_time = time.time()
|
|
# information(f"{event_name} has started.")
|
|
result = function(*args, **kwargs)
|
|
end_time = time.time()
|
|
# compute the time took in 2 decimal places
|
|
time_took = round(end_time - start_time, 2)
|
|
information(f"{event_name} has finished in {time_took} seconds.\n")
|
|
return result
|
|
|
|
return wrapped_function
|
|
|
|
return wrapper
|
|
|
|
|
|
def handle_exceptions(function: Callable) -> Callable:
|
|
""" """
|
|
|
|
def wrapper(*args, **kwargs):
|
|
return function(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
class LiveProgressReporter(rich.live.Live):
|
|
"""This class is a wrapper around `rich.live.Live` that provides the live progress
|
|
reporting functionality.
|
|
|
|
Args:
|
|
number_of_steps (int): The number of steps to be finished.
|
|
"""
|
|
|
|
def __init__(self, number_of_steps: int):
|
|
class TimeElapsedColumn(rich.progress.ProgressColumn):
|
|
def render(self, task: "rich.progress.Task") -> rich.text.Text:
|
|
elapsed = task.finished_time if task.finished else task.elapsed
|
|
if elapsed is None:
|
|
return rich.text.Text("--.-", style="progress.elapsed")
|
|
delta = f"{elapsed:.1f} s"
|
|
return rich.text.Text(str(delta), style="progress.elapsed")
|
|
|
|
self.step_progress = rich.progress.Progress(
|
|
TimeElapsedColumn(), rich.progress.TextColumn("{task.description}")
|
|
)
|
|
|
|
self.overall_progress = rich.progress.Progress(
|
|
TimeElapsedColumn(),
|
|
rich.progress.BarColumn(),
|
|
rich.progress.TextColumn("{task.description}"),
|
|
)
|
|
|
|
self.group = rich.console.Group(
|
|
rich.panel.Panel(rich.console.Group(self.step_progress)),
|
|
self.overall_progress,
|
|
)
|
|
|
|
self.overall_task_id = self.overall_progress.add_task("", total=number_of_steps)
|
|
self.number_of_steps = number_of_steps
|
|
self.current_step = 0
|
|
self.overall_progress.update(
|
|
self.overall_task_id,
|
|
description=(
|
|
f"[bold #AAAAAA]({self.current_step} out of"
|
|
f" {self.number_of_steps} steps finished)"
|
|
),
|
|
)
|
|
super().__init__(self.group)
|
|
|
|
def __enter__(self) -> "LiveProgressReporter":
|
|
"""Overwrite the `__enter__` method for the correct return type."""
|
|
self.start(refresh=self._renderable is not None)
|
|
return self
|
|
|
|
def start_a_step(self, step_name: str):
|
|
"""Start a step and update the progress bars."""
|
|
self.current_step_name = step_name
|
|
self.current_step_id = self.step_progress.add_task(
|
|
f"{self.current_step_name} has started."
|
|
)
|
|
|
|
def finish_the_current_step(self):
|
|
"""Finish the current step and update the progress bars."""
|
|
self.step_progress.stop_task(self.current_step_id)
|
|
self.step_progress.update(
|
|
self.current_step_id, description=f"{self.current_step_name} has finished."
|
|
)
|
|
self.current_step += 1
|
|
self.overall_progress.update(
|
|
self.overall_task_id,
|
|
description=(
|
|
f"[bold #AAAAAA]({self.current_step} out of"
|
|
f" {self.number_of_steps} steps finished)"
|
|
),
|
|
advance=1,
|
|
)
|
|
if self.current_step == self.number_of_steps:
|
|
self.end()
|
|
|
|
def end(self):
|
|
"""End the live progress reporting."""
|
|
self.overall_progress.update(
|
|
self.overall_task_id,
|
|
description="[bold green]Your CV is rendered!",
|
|
)
|