Skip to main content

Python terminal colored logger

Project description

tclogger

Python terminal colored logger

Install

pip install tclogger --upgrade

Usage

Run example:

python example.py

See: example.py

import sys
import tclogger
import time

from datetime import timedelta
from zoneinfo import ZoneInfo

from tclogger import TCLogger, logger, TCLogstr, logstr, colored, decolored
from tclogger import Runtimer, OSEnver, shell_cmd
from tclogger import get_now_ts, get_now_str, get_now_ts_str
from tclogger import TIMEZONE, set_timezone, tcdatetime
from tclogger import ts_to_str, str_to_ts, dt_to_str, unify_ts_and_str
from tclogger import CaseInsensitiveDict, dict_to_str, dict_get, dict_set
from tclogger import FileLogger
from tclogger import TCLogbar, TCLogbarGroup
from tclogger import brk, brc, brp


def test_logger_verbose():
    logger.note("Hello ", end="")
    logger.warn("You should not see this message", verbose=False)
    logger.mesg("World")
    logger.verbose = False
    logger.warn("You should not see later messages")
    logger.verbose = True
    logger.set_indent(2)
    logger.success("You should see this message, with indent")


def test_run_timer_and_logger():
    with Runtimer():
        logger.note(tclogger.__file__)
        logger.mesg(get_now_ts())
        logger.success(get_now_str())
        logger.note(f"Now: {logstr.mesg(get_now_str())}, ({logstr.file(get_now_ts())})")


def test_now_and_timezone():
    # Asia/Shanghai
    logger.success(TIMEZONE)
    logger.success(get_now_str())
    dt = tcdatetime.fromisoformat("2024-10-31")
    logger.success(dt)
    # Europe/London
    set_timezone("Europe/London")
    logger.note(get_now_str())
    dt = tcdatetime(year=2024, month=10, day=31)
    logger.note(dt)
    logger.note(tcdatetime.strptime("2024-10-31", "%Y-%m-%d"))
    logger.note(tcdatetime.now())
    dt = tcdatetime.fromisoformat("2024-10-31")
    logger.note(dt)
    logger.note(dt.strftime("%Y-%m-%d %H:%M:%S"))
    # America/New_York
    set_timezone("America/New_York")
    logger.warn(get_now_str())
    dt = tcdatetime.fromisoformat("2024-10-31")
    logger.warn(dt)
    logger.warn(dt.astimezone(ZoneInfo("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S"))
    # Asia/Shanghai
    set_timezone("Asia/Shanghai")
    logger.success(get_now_str())


def test_dt_to_str():
    dt1 = timedelta(seconds=12)
    logger.note(f"dt1: {logstr.success(dt_to_str(dt1))}")
    dt2 = timedelta(seconds=60 * 24 + 12)
    logger.note(f"dt2: {logstr.success(dt_to_str(dt2))}")
    dt3 = timedelta(seconds=3600 * 8 + 60 * 24 + 12)
    logger.note(f"dt3: {logstr.success(dt_to_str(dt3))}")
    dt4 = timedelta(seconds=3600 * 24 * 1 + 3600 * 8 + 60 * 24 + 12)
    logger.note(f"dt4: {logstr.success(dt_to_str(dt4))}")

    t_ts = 1700000000
    t_ts, t_str = unify_ts_and_str(t_ts)
    logger.mesg(f"t_ts: {logstr.success(t_ts)}, t_str: {logstr.success(t_str)}")
    t_str = "2021-08-31 08:53:20"
    t_ts, t_str = unify_ts_and_str(t_str)
    logger.mesg(f"t_ts: {logstr.success(t_ts)}, t_str: {logstr.success(t_str)}")


def test_color():
    s1 = colored("hello", color="green", bg_color="bg_red", fonts=["bold", "blink"])
    s2 = colored("world", color="red", bg_color="bg_blue", fonts=["bold", "underline"])
    s3 = colored(f"BEG {s1} __ {s2} END")
    logger.note(s3)
    logger.success(s3)
    s4 = decolored(logstr.success(s3))
    print(s4)


def test_case_insensitive_dict():
    d = CaseInsensitiveDict()
    d["Hello"] = "old world"
    print(d["hello"])
    print(d)
    d["hELLo"] = "New WORLD"
    print(d["HEllO"])
    print(d)


def test_dict_get_and_set():
    d = {
        "owner": {"name": "Alice", "mid": 12345},
        "tags": ["tag1", "tag2", "tag3"],
        "children": [
            {
                "owner": {"name": "Bob", "mid": 54321},
                "tags": ["tag4", "tag5", "tag6"],
            }
        ],
    }
    print(dict_get(d, "owner.name"))
    print(dict_get(d, ["children", 0, "owner", "mid"]))
    dict_set(d, "owner.name", "Alice2")
    print(d)
    dict_set(d, ["owner", "mid"], 56789)
    print(d)
    print(dict_get(d, "owner.none", default="NotExist"))
    dict_set(d, "owner.new", "NewValue")
    print(d)
    dict_set(d, ["children", 1, "owner", "name"], "Bob2")
    print(d)
    dict_set(d, ["tags", 3], "tagsX")
    print(d)


def test_dict_to_str():
    d = {
        "hello": "world",
        "now": get_now_str(),
        "list": [1, 2, 3, [4, 5], "6"],
        "nested": {"key1": "value1", "key2": "value2", "key_3": {"subkey": "subvalue"}},
    }
    s = dict_to_str(d, add_quotes=True, max_depth=1)
    logger.success(s)
    s = dict_to_str(d, add_quotes=False, is_colored=False, max_depth=0)
    print(s)


def test_file_logger():
    file_logger = FileLogger(Path(__file__).parent / "test.log")
    file_logger.log("This is an error message", "error")


def test_align_dict_list():
    data = {
        "_id": None,
        "view_avg": 15175,
        "view_maxn": [94092954, 86624275, 68368263, 57713196, 53493614],
        "view_percentile": [39, 152, 254, 539, 3032, 13602, 51956, 282149, 94092954],
        "coin_avg": 57,
        "coin_maxn": [3093375, 2021980, 1420923, 1354206, 1312931],
        "coin_percentile": [0, 0, 0, 1, 6, 24, 76, 682, 3093375],
        "danmaku_avg": 26,
        "danmaku_maxn": [762005, 365521, 349354, 335414, 334935],
        "danmaku_percentile": [0, 0, 0, 0, 2, 12, 57, 353, 762005],
        "percentiles": [0.2, 0.4, 0.5, 0.6, 0.8, 0.9, 0.95, 0.99, 1.0],
        "sub_lists": {
            "sub1": [1, 2, 4, 5, 6],
            "sub2": [21, 2, 35, 43, 89],
            "sub3": ["a", "abc", "gh", "jkl", "qerq"],
            "sub4": ["x", "ef", "i", "mkns", "adfa"],
        },
    }
    print(dict_to_str(data, align_list=True))


def test_list_of_dicts():
    dict_data = {
        "list_of_lists": [[1, 2, 3], ["a", "b", "c"]],
        "list_of_dicts": [{"key1": "dict1"}, {"key2": "dict2", "key3": "dict3"}],
        "empty_list": [],
        "empty_dict": {},
    }
    print(dict_to_str(dict_data, align_list=True))
    print()
    list_data = [{"key1": "val1"}, {"key2": "val2"}, {"key10": "val10"}]
    print(dict_to_str(list_data, align_list=True))


def test_logbar():
    epochs = 3
    total = 1000000
    logbar = TCLogbar(
        total=total, show_datetime=False, flush_interval=0.1, grid_mode="symbol"
    )
    for epoch in range(epochs):
        for i in range(total):
            logbar.update(increment=1)
            logbar.set_head(f"[{epoch+1}/{epochs}]")
        logbar.grid_mode = "shade"
        logbar.set_desc("THIS IS A SO LONG DESC WHICH IS USED TO TEST LINE UP")
        logbar.reset()


def test_logbar_group():
    epochs = 3
    total = 100
    sub_total = 1000
    epoch_bar = TCLogbar(total=epochs)
    epoch_bar.set_desc(f"[0/{epochs}]")
    progress_bar = TCLogbar(total=total)
    sub_progress_bar = TCLogbar(total=sub_total)
    TCLogbarGroup([epoch_bar, progress_bar, sub_progress_bar], show_at_init=True)
    # TCLogbarGroup([epoch_bar, progress_bar, sub_progress_bar], show_at_init=False)
    # print("This is a noise line to test lazy blank prints of logbar group.")
    # epoch_bar.update(0)
    for epoch in range(epochs):
        for i in range(total):
            for j in range(sub_total):
                sub_progress_bar.update(1, desc=f"[{j+1}/{sub_total}]")
                time.sleep(0.01)
            sub_progress_bar.reset()
            progress_bar.update(1, desc=f"[{i+1}/{total}]")
        progress_bar.reset()
        epoch_bar.set_desc()
        epoch_bar.update(1, desc=f"[{epoch+1}/{epochs}]", flush=True)


def test_logbar_total():
    total = 500

    logbar = TCLogbar()
    for i in range(total):
        logbar.update(1)
        time.sleep(0.001)
    logbar.flush()
    print()

    logbar = TCLogbar(total=total)
    for i in range(total + 250):
        logbar.update(1)
        time.sleep(0.01)


def test_logbar_verbose():
    total = 1000
    logbar1 = TCLogbar(total=total, show_datetime=False, head="bar1", verbose=False)
    logger.note("> Here should NOT show bar1")
    for i in range(total):
        logbar1.update(1)
    print()

    logbar2 = TCLogbar(total=total, show_datetime=False, head="bar2", verbose=True)
    logger.note("> Here should show bar2")
    for i in range(total):
        logbar2.update(1)
    print()

    logger.note("> Here should NOT show bar1 and bar2")
    TCLogbarGroup([logbar1, logbar2], verbose=False)
    print()

    logger.note("> Here should show bar1 and bar2")
    TCLogbarGroup([logbar1, logbar2], verbose=True)
    print()


def test_decorations():
    text = "Hello World"
    logger.note(f"Brackets: {logstr.mesg(brk(text))}")
    logger.note(f"Braces  : {logstr.mesg(brc(text))}")
    logger.note(f"Parens  : {logstr.mesg(brp(text))}")


if __name__ == "__main__":
    test_logger_verbose()
    test_run_timer_and_logger()
    test_now_and_timezone()
    test_dt_to_str()
    test_color()
    test_case_insensitive_dict()
    test_dict_get_and_set()
    test_dict_to_str()
    test_align_dict_list()
    test_list_of_dicts()
    test_file_logger()
    test_logbar()
    test_logbar_group()
    test_logbar_total()
    test_logbar_verbose()
    test_decorations()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tclogger-1.2.4.tar.gz (18.6 kB view details)

Uploaded Source

Built Distribution

tclogger-1.2.4-py3-none-any.whl (18.6 kB view details)

Uploaded Python 3

File details

Details for the file tclogger-1.2.4.tar.gz.

File metadata

  • Download URL: tclogger-1.2.4.tar.gz
  • Upload date:
  • Size: 18.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for tclogger-1.2.4.tar.gz
Algorithm Hash digest
SHA256 3bc5aaafe34864ebf4df38210f510df8860ad22c35d8cc47d96a08f90c0164d8
MD5 40c334a02dee51379c4ca2911be3af20
BLAKE2b-256 135214d3b7584bfd7bd9a0a0736b3ee15c1875eda600a78a96b119f897929f6a

See more details on using hashes here.

File details

Details for the file tclogger-1.2.4-py3-none-any.whl.

File metadata

  • Download URL: tclogger-1.2.4-py3-none-any.whl
  • Upload date:
  • Size: 18.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for tclogger-1.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 411c3535a77109139b27b70baba6b4388effd04dbec4652a0bfc5d19e18256c6
MD5 bd884f7f5a23a067504b4ab8d3f91277
BLAKE2b-256 f029b3d4a0f6018225a012dd22d74c8c99bf80ec170cd7caea8bf9b6719d04d2

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page