{"id":23002875,"url":"https://github.com/likianta/lk-logger","last_synced_at":"2025-08-30T07:07:09.390Z","repository":{"id":43972636,"uuid":"294447505","full_name":"likianta/lk-logger","owner":"likianta","description":"Python advanced print with varnames.","archived":false,"fork":false,"pushed_at":"2025-06-20T08:50:18.000Z","size":5686,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-24T22:21:16.449Z","etag":null,"topics":["debug","debugging","logger","print","python","python-print","varname"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/likianta.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.zh.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-09-10T15:22:11.000Z","updated_at":"2025-06-20T08:50:22.000Z","dependencies_parsed_at":"2023-12-04T03:20:35.044Z","dependency_job_id":"246e953b-43f2-49ab-897d-c280ec622c0d","html_url":"https://github.com/likianta/lk-logger","commit_stats":{"total_commits":203,"total_committers":2,"mean_commits":101.5,"dds":"0.0049261083743842304","last_synced_commit":"53cf5153e83c6bbe956f8e302e5035cc2f403b20"},"previous_names":[],"tags_count":52,"template":false,"template_full_name":null,"purl":"pkg:github/likianta/lk-logger","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/likianta%2Flk-logger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/likianta%2Flk-logger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/likianta%2Flk-logger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/likianta%2Flk-logger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/likianta","download_url":"https://codeload.github.com/likianta/lk-logger/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/likianta%2Flk-logger/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272816339,"owners_count":24997760,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["debug","debugging","logger","print","python","python-print","varname"],"created_at":"2024-12-15T07:12:30.787Z","updated_at":"2025-08-30T07:07:08.987Z","avatar_url":"https://github.com/likianta.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LK Logger\r\n\r\n[![PyPI version](https://badge.fury.io/py/lk-logger.svg)](https://badge.fury.io/py/lk-logger) [![Downloads](https://static.pepy.tech/badge/lk-logger)](https://pepy.tech/project/lk-logger) [![Downloads](https://static.pepy.tech/badge/lk-logger/month)](https://pepy.tech/project/lk-logger)\r\n\r\n[中文版](https://blog.csdn.net/Likianta/article/details/145509829)\r\n\r\nAn alternative to Python built-in `print` function with rich features.\r\n\r\n![image-20240517150306400](.assets/image-20240517150306400.png)\r\n\r\n## Features\r\n\r\n-   Print with source path, function name and varnames in console.\r\n-   Code highlights.\r\n-   As simple as using `print` like usual.\r\n-   Globally replace `print`.\r\n-   Less code changes, non-intrusive.\r\n\r\n## Installation\r\n\r\n```sh\r\npip install lk-logger\r\n```\r\n\r\nRequires Python 3.8 and above. The latest version is 6.0.0 or higher.\r\n\r\n## Show Me The Code\r\n\r\n### Hello world\r\n\r\n```py\r\nimport lk_logger\r\nlk_logger.setup()\r\nprint('hello world')\r\n```\r\n\r\nIt shows source path, function name (or module name in top lines) besides main content:\r\n\r\n![image-20240517175917191](.assets/image-20240517175917191.png)\r\n\r\n### Print with variant names\r\n\r\n```py\r\nimport lk_logger\r\nlk_logger.setup(show_varnames=True)\r\na = 1\r\nb = 2\r\nprint(a, b, a + b)\r\n```\r\n\r\n`lk-logger` detects the variant or expression from the source code. It is similar but much shorter than the traditional way (`print(f'a = {}; b = {}; a + b = {}'.format(a, b, a + b))`):\r\n\r\n![image-20240517154631421](.assets/image-20240517154631421.png)\r\n\r\n### Prints from third party libraries\r\n\r\nFor libraries from \"site-packages\" directory, if they have used `print(...)` in their source code, `lk-logger` will shorten the source path prefixes to be the library names with square brackets.\r\n\r\n```py\r\nimport lk_logger\r\nlk_logger.setup(quiet=True, show_varnames=True)\r\n\r\nimport depsland  # pip install depsland\r\n# ^ there are some prints in depsland initial time.\r\n#   let's see the print results.\r\nprint(depsland.__version__)\r\n```\r\n\r\n![image-20240517164439457](.assets/image-20240517164439457.png)\r\n\r\n### Highlighting styles\r\n\r\n```py\r\nimport lk_logger\r\nlk_logger.setup(quiet=True)\r\n\r\nprint('[red]hello[/] [yellow]world[/]', ':r')\r\n# ^ notice ':r' mark, we'll explain later.\r\n\r\nprint(':d', 'divider line')\r\n\r\n# verbosities\r\nprint(':v1', 'debug message')\r\nprint(':v2', 'info message')\r\nprint(':v3', 'warning message')\r\nprint(':v4', 'error message')\r\nprint(':v5', 'critical message')\r\n```\r\n\r\n![image-20240517180622736](.assets/image-20240517180622736.png)\r\n\r\n### Exceptions\r\n\r\n`lk-logger` depends on `rich` library, it shows pretty exception panel for tracebacks:\r\n\r\n```py\r\nimport lk_logger\r\nlk_logger.setup(quiet=True)\r\n# try to raise an error\r\nx = 1 / 0\r\n```\r\n\r\n![image-20240517180922042](.assets/image-20240517180922042.png)\r\n\r\n### Using in IPython\r\n\r\n![image-20240517181302027](.assets/image-20240517181302027.png)\r\n\r\n### Indexing and timing\r\n\r\n```py\r\nimport lk_logger\r\nlk_logger.setup(quiet=True)\r\n\r\nprint(':d', 'indexing')\r\nprint(':i', 'aaa')\r\nprint(':i', 'bbb')\r\nprint(':i', 'ccc')\r\nprint(':i0', 'reset counter')\r\nprint(':i', 'ddd')\r\nprint(':i', 'eee')\r\nprint(':i', 'fff')\r\n\r\nprint(':d', 'timing')\r\nfrom time import sleep\r\nsleep(0.1)\r\nprint(':t', '... in a short delay')\r\nsleep(1)\r\nprint(':t', '... in a little long delay')\r\nsleep(5)\r\nprint(':t', '... in a long delay')\r\n```\r\n\r\n![image-20240517181932571](.assets/image-20240517181932571.png)\r\n\r\n### Reflect source to parent caller\r\n\r\n```py\r\nimport lk_logger\r\nlk_logger.setup(quiet=True)\r\n\r\ndef borrow_a_book(name: str) -\u003e None:\r\n    # use ':p' to point to the parent frame\r\n    print(f'user borrowed \"{name}\"', ':p')\r\n\r\nrecord = []\r\nrecord.append(('shawn', borrow_a_book('python crash course')))\r\n\r\n# after some process\r\n...\r\n\r\nrecord.append(('alice', borrow_a_book('deep learning with python')))\r\n```\r\n\r\n![image-20240517182639628](.assets/image-20240517182639628.png)\r\n\r\nThe source info is helpful for developer to track different callers to the same function.\r\n\r\n### Redirect printing to other streamers\r\n\r\n```py\r\nimport atexit\r\nimport lk_logger\r\nfrom lk_logger import parallel_printing\r\n\r\nlk_logger.setup(quiet=True)\r\n\r\nclass MyLogger:\r\n    def __init__(self):\r\n        self._buffer = []\r\n        atexit.register(self.close)\r\n    \r\n    def write(self, msg: str):\r\n        self._buffer.append(msg)\r\n        \r\n    def close(self) -\u003e None:\r\n        with open('log.txt', 'w') as f:\r\n            f.write('\\n'.join(self._buffer))\r\n\r\nclass MyGui:\r\n    def update_ui(self, msg: str) -\u003e None:\r\n        \"\"\" send message to GUI log panel. \"\"\"\r\n        ...\r\n\r\nmylogger = MyLogger()\r\nmygui = MyGui()\r\n\r\nwith parallel_printing(\r\n    mylogger.write,\r\n    mygui.update_ui,\r\n    inherit=True,  # default True. \r\n    # ^ change to False to prevent default behavior (i.e. printing to console).\r\n):\r\n    print('hello world!')\r\n```\r\n\r\n### More markups\r\n\r\nHere is a list of all available markups. You can also find them from \"examples\" folder.\r\n\r\n```py\r\nimport lk_logger\r\nfrom rich.markdown import Markdown\r\n\r\nlk_logger.setup(show_varnames=True)\r\n\r\n# -----------------------------------------------------------------------------\r\nprint(':dr', '`:e` is [yellow][u]E[/]xception[/]')\r\n\r\ntry:\r\n    raise Exception('this is an exception with locals info')\r\nexcept Exception as e:\r\n    print(':e1', e)\r\n\r\n# -----------------------------------------------------------------------------\r\nprint(':dr', '`:i` is [yellow][u]I[/]ndexing[/]')\r\n\r\nprint(':i', 'sunday')\r\nprint(':i', 'monday')\r\nprint(':i', 'tuesday')\r\nprint(':i', 'wednesday')\r\nprint(':i', 'thursday')\r\nprint(':i', 'friday')\r\nprint(':i', 'saturday')\r\nprint(':i0')\r\nprint(':i', 'sunday in new week')\r\nprint(':i', 'monday in new week')\r\nprint(':i', 'tuesday in new week')\r\nprint(':i', 'wednesday in new week')\r\nprint(':i', 'thursday in new week')\r\nprint(':i', 'friday in new week')\r\nprint(':i', 'saturday in new week')\r\n\r\n# -----------------------------------------------------------------------------\r\nprint(':dr', '`:l` is [yellow][u]L[/]ong/[u]L[/]oose[/] format')\r\n\r\nprint(':l', {\r\n    'name': 'John',\r\n    'age': 30,\r\n    'address': {\r\n        'country': 'USA',\r\n        'city': 'New York',\r\n        'street': 'Wall Street'\r\n    }\r\n})\r\n\r\n# -----------------------------------------------------------------------------\r\nprint(':dr', '`:p` is [yellow][u]P[/]arent[/] frame')\r\n\r\n\r\ndef func1():\r\n    print('who is calling me?')\r\n    print('i am', ':p1')\r\n    return 'ok'\r\n\r\n\r\nresponse = func1()\r\nprint(response)\r\n\r\n# -----------------------------------------------------------------------------\r\nprint(':dr', '`:r` is [yellow][u]R[/]ich[/] format')\r\n\r\nprint(':r', '[cyan]hello[/] [yellow]world[/]')\r\n\r\n# print a rich renderable object\r\nprint(':r1', Markdown('''\r\n# Hello World\r\n\r\nThis is a markdown document.\r\n\r\n- item 1\r\n- item 2\r\n- item 3\r\n\r\nFind more usages at [rich](https://github.com/textualize/rich) documentation.\r\n'''))\r\n\r\n# automatically convert a dict to a table\r\nprint(':r2', {\r\n    'Name': ('Alice', 'Bob', 'Charlie'),\r\n    'Age': (18, 19, 20),\r\n    'City': ('Shanghai', 'Beijing', 'Guangzhou'),\r\n})\r\n\r\n# -----------------------------------------------------------------------------\r\nprint(':dr', '`:s` [yellow][u]S[/]hort/[u]S[/]imple/[u]S[/]ingle-line[/] format')\r\n\r\na, b = 1, 2\r\nprint(':s', a, b, a + b)  # without varnames\r\nprint(':s1', a, b, a + b)  # similar to built-in print (but kept color style)\r\nprint(':s2', a, b, a + b)  # totally same with built-in print\r\n\r\n# -----------------------------------------------------------------------------\r\nprint(':dr', '`:t` is [yellow][u]T[/]iming[/]')\r\n\r\nprint(':t', 'for now')\r\n\r\n# -----------------------------------------------------------------------------\r\nprint(':dr', '`:v` is [yellow][u]V[/]erbosity[/]')\r\n\r\nprint(':v0', 'this is a TRACE message')\r\nprint(':v1', 'this is a DEBUG message')\r\nprint(':v2', 'this is a INFO  message')\r\nprint(':v3', 'this is a WARN  message')\r\nprint(':v4', 'this is a ERROR message')\r\nprint(':v5', 'this is a FATAL message')\r\n\r\na, b, c = 1, 2, 3\r\nprint(':v', a, b, c)\r\n```\r\n\r\n![image-20240517185519671](.assets/image-20240517185519671.png)\r\n\r\n## Gallery / Code Screenshots\r\n\r\nProjects using `lk-logger` for their prints:\r\n\r\n![image-20240517155028545](.assets/image-20240517155028545.png)\r\n\r\n![image-20240517162243806](.assets/image-20240517162243806.png)\r\n\r\n![image-20240524071958](.assets/image-20240524071958.png)\r\n\r\n![image-20240517190059304](.assets/image-20240517190059304.png)\r\n\r\n*More...*\r\n\r\n## Markup References\r\n\r\nA markup is a string starts with colon symbol (`:`), positioned at the first or the last among positional arguments, and came up with multiple letters and digits.\r\n\r\nFor example:\r\n\r\n```python\r\nprint(':i', 'monday')\r\nprint(':i', 'tuesday')\r\nprint(':i', 'wednesday')\r\n```\r\n\r\nIt prints weekdays with a numeric prefix.\r\n\r\n**Here is a list of all available marks:**\r\n\r\n| Mark | Description                        |\r\n| :--- | :--------------------------------- |\r\n| `:d` | Divider line                       |\r\n| `:e` | Exception                          |\r\n| `:f` | Flush                              |\r\n| `:i` | Index                              |\r\n| `:l` | Long/Loose format (multiple lines) |\r\n| `:p` | Parent frame                       |\r\n| `:r` | Rich style                         |\r\n| `:s` | Short/Simple/Single-line format    |\r\n| `:t` | Timestamp                          |\r\n| `:v` | Verbosity level                    |\r\n\r\n**Markup options:**\r\n\r\n```\r\n* d0: divider line\r\n  d1: divider block                               *(not supported)*\r\n* e0: exception trace back\r\n  e1: exception trace back with showing locals\r\n  e2: enter pdb                                   *(not supported)*\r\n* f0: flush\r\n  f1: flush cutoff\r\n  f2: flush eddy               *(not a good option, maybe removed)*\r\n  i0: reset index\r\n* i1: update index\r\n  i2: scoped counter\r\n  i3: progress                                    *(not supported)*\r\n* l0: long / loose / expanded (multiple lines)\r\n  l1: inspect object\r\n  p0: self layer\r\n* p1: parent layer\r\n  p2: grandparent layer                    *(be careful using p2+)*\r\n  p3: great-grandparent layer\r\n  p4: and so on...\r\n* r0: rich style\r\n  r1: rich object (rich.table.Table, rich.panel.Panel, etc.)\r\n  r2: auto detect rich format (for a limit set of types)\r\n* s0: short / simple / single line\r\n  s1: builtin-like print (remains markup features)\r\n  s2: builtin print\r\n  t0: reset timer\r\n* t1: stop timer and show statistics\r\n  t2: temporary timer\r\n* v0: trace / debug / hint (gray)\r\n  v1: negative info (magenta)\r\n  v2: positive info (blue)\r\n  v3: weak success (green dim)\r\n  v4: success (green)\r\n  v5: weak warning (yellow dim)\r\n  v6: warning (yellow)\r\n  v7: weak error / failure (red dim)\r\n  v8: error / failure (red)\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flikianta%2Flk-logger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flikianta%2Flk-logger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flikianta%2Flk-logger/lists"}