mirror of
https://github.com/ArchiveBox/ArchiveBox.git
synced 2026-09-12 19:50:57 +05:00
124 lines
4.0 KiB
Python
124 lines
4.0 KiB
Python
__package__ = "archivebox.misc"
|
|
|
|
# Bootable logging primitives (Rich console, ANSI colors, stdout/stderr helpers).
|
|
# MUST NOT import archivebox.config, archivebox.core, or Django — this module is
|
|
# loaded via config/constants.py during pre-bootstrap, before settings or apps
|
|
# are ready. Post-bootstrap CLI logging helpers live in logging_util.py.
|
|
|
|
import sys
|
|
from collections import defaultdict
|
|
from random import randint
|
|
|
|
from rich.console import Console
|
|
from rich.highlighter import Highlighter
|
|
|
|
# SETUP RICH CONSOLE / TTY detection / COLOR / PROGRESS BARS
|
|
# Disable wrapping - use soft_wrap=True and large width so text flows naturally
|
|
# Colors are preserved, just no hard line breaks inserted
|
|
CONSOLE = Console(width=32768, soft_wrap=True, force_terminal=True)
|
|
STDERR = Console(stderr=True, width=32768, soft_wrap=True, force_terminal=True)
|
|
IS_TTY = sys.stdout.isatty()
|
|
|
|
|
|
class AttrDict(dict):
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__()
|
|
self.update(*args, **kwargs)
|
|
|
|
@classmethod
|
|
def _wrap(cls, value):
|
|
if isinstance(value, dict) and not isinstance(value, AttrDict):
|
|
return cls(value)
|
|
if isinstance(value, list):
|
|
return [cls._wrap(item) for item in value]
|
|
if isinstance(value, tuple):
|
|
return tuple(cls._wrap(item) for item in value)
|
|
return value
|
|
|
|
def __setitem__(self, key, value):
|
|
super().__setitem__(key, self._wrap(value))
|
|
|
|
def update(self, *args, **kwargs):
|
|
for key, value in dict(*args, **kwargs).items():
|
|
self[key] = value
|
|
|
|
def __getattr__(self, key):
|
|
try:
|
|
return self[key]
|
|
except KeyError as err:
|
|
raise AttributeError(key) from err
|
|
|
|
|
|
class RainbowHighlighter(Highlighter):
|
|
def highlight(self, text):
|
|
for index in range(len(text)):
|
|
text.stylize(f"color({randint(90, 98)})", index, index + 1)
|
|
|
|
|
|
rainbow = RainbowHighlighter()
|
|
|
|
|
|
DEFAULT_CLI_COLORS = AttrDict(
|
|
{
|
|
"reset": "\033[00;00m",
|
|
"lightblue": "\033[01;30m",
|
|
"lightyellow": "\033[01;33m",
|
|
"lightred": "\033[01;35m",
|
|
"red": "\033[01;31m",
|
|
"green": "\033[01;32m",
|
|
"blue": "\033[01;34m",
|
|
"white": "\033[01;37m",
|
|
"black": "\033[01;30m",
|
|
},
|
|
)
|
|
ANSI = AttrDict({k: "" for k in DEFAULT_CLI_COLORS.keys()})
|
|
|
|
COLOR_DICT = defaultdict(
|
|
lambda: [(0, 0, 0), (0, 0, 0)],
|
|
{
|
|
"00": [(0, 0, 0), (0, 0, 0)],
|
|
"30": [(0, 0, 0), (0, 0, 0)],
|
|
"31": [(255, 0, 0), (128, 0, 0)],
|
|
"32": [(0, 200, 0), (0, 128, 0)],
|
|
"33": [(255, 255, 0), (128, 128, 0)],
|
|
"34": [(0, 0, 255), (0, 0, 128)],
|
|
"35": [(255, 0, 255), (128, 0, 128)],
|
|
"36": [(0, 255, 255), (0, 128, 128)],
|
|
"37": [(255, 255, 255), (255, 255, 255)],
|
|
},
|
|
)
|
|
|
|
|
|
# Logging Helpers (DEPRECATED, use rich.print instead going forward)
|
|
def stdout(*args, color: str | None = None, prefix: str = "", config: dict | None = None) -> None:
|
|
ansi = DEFAULT_CLI_COLORS if (config or {}).get("USE_COLOR") else ANSI
|
|
|
|
if color:
|
|
strs = [ansi[color], " ".join(str(a) for a in args), ansi["reset"], "\n"]
|
|
else:
|
|
strs = [" ".join(str(a) for a in args), "\n"]
|
|
|
|
sys.stdout.write(prefix + "".join(strs))
|
|
|
|
|
|
def stderr(*args, color: str | None = None, prefix: str = "", config: dict | None = None) -> None:
|
|
ansi = DEFAULT_CLI_COLORS if (config or {}).get("USE_COLOR") else ANSI
|
|
|
|
if color:
|
|
strs = [ansi[color], " ".join(str(a) for a in args), ansi["reset"], "\n"]
|
|
else:
|
|
strs = [" ".join(str(a) for a in args), "\n"]
|
|
|
|
sys.stderr.write(prefix + "".join(strs))
|
|
|
|
|
|
def hint(text: tuple[str, ...] | list[str] | str, prefix=" ", config: dict | None = None) -> None:
|
|
ansi = DEFAULT_CLI_COLORS if (config or {}).get("USE_COLOR") else ANSI
|
|
|
|
if isinstance(text, str):
|
|
stderr(f"{prefix}{ansi['lightred']}Hint:{ansi['reset']} {text}")
|
|
else:
|
|
stderr(f"{prefix}{ansi['lightred']}Hint:{ansi['reset']} {text[0]}")
|
|
for line in text[1:]:
|
|
stderr(f"{prefix} {line}")
|