Skip to main content

Python print with source map and varnames.

Project description

LK Logger

PyPI version Downloads Downloads

中文版

An alternative to Python built-in print function with rich features.

image-20240517150306400

Features

  • Print with source path, function name and varnames in console.
  • Code highlights.
  • As simple as using print like usual.
  • Globally replace print.
  • Less code changes, non-intrusive.

Installation

pip install lk-logger

Requires Python 3.8 and above. The latest version is 5.7.0 or higher.

Show Me The Code

Hello world

import lk_logger
lk_logger.setup()
print('hello world')

It shows source path, function name (or module name in top lines) besides main content:

image-20240517175917191

Print with variant names

import lk_logger
lk_logger.setup(show_varnames=True)
a = 1
b = 2
print(a, b, a + b)

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))):

image-20240517154631421

Prints from third party libraries

For 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.

import lk_logger
lk_logger.setup(quiet=True, show_varnames=True)

import depsland  # pip install depsland
# ^ there are some prints in depsland initial time.
#   let's see the print results.
print(depsland.__version__)

image-20240517164439457

Highlighting styles

import lk_logger
lk_logger.setup(quiet=True)

print('[red]hello[/] [yellow]world[/]', ':r')
# ^ notice ':r' mark, we'll explain later.

print(':d', 'divider line')

# verbosities
print(':v1', 'debug message')
print(':v2', 'info message')
print(':v3', 'warning message')
print(':v4', 'error message')
print(':v5', 'critical message')

image-20240517180622736

Exceptions

lk-logger depends on rich library, it shows pretty exception panel for tracebacks:

import lk_logger
lk_logger.setup(quiet=True)
# try to raise an error
x = 1 / 0

image-20240517180922042

Using in IPython

image-20240517181302027

Indexing and timing

import lk_logger
lk_logger.setup(quiet=True)

print(':d', 'indexing')
print(':i', 'aaa')
print(':i', 'bbb')
print(':i', 'ccc')
print(':i0', 'reset counter')
print(':i', 'ddd')
print(':i', 'eee')
print(':i', 'fff')

print(':d', 'timing')
from time import sleep
sleep(0.1)
print(':t', '... in a short delay')
sleep(1)
print(':t', '... in a little long delay')
sleep(5)
print(':t', '... in a long delay')

image-20240517181932571

Reflect source to parent caller

import lk_logger
lk_logger.setup(quiet=True)

def borrow_a_book(name: str) -> None:
    # use ':p' to point to the parent frame
    print(f'user borrowed "{name}"', ':p')

record = []
record.append(('shawn', borrow_a_book('python crash course')))

# after some process
...

record.append(('alice', borrow_a_book('deep learning with python')))

image-20240517182639628

The source info is helpful for developer to track different callers to the same function.

Redirect printing to other streamers

import atexit
import lk_logger
from lk_logger import parallel_printing

lk_logger.setup(quiet=True)

class MyLogger:
    def __init__(self):
        self._buffer = []
        atexit.register(self.close)
    
    def write(self, msg: str):
        self._buffer.append(msg)
        
    def close(self) -> None:
        with open('log.txt', 'w') as f:
            f.write('\n'.join(self._buffer))

class MyGui:
    def update_ui(self, msg: str) -> None:
        """ send message to GUI log panel. """
        ...

mylogger = MyLogger()
mygui = MyGui()

with parallel_printing(
    mylogger.write,
    mygui.update_ui,
    inherit=True,  # default True. 
    # ^ change to False to prevent default behavior (i.e. printing to console).
):
    print('hello world!')

More markups

Here is a list of all available markups. You can also find them from "examples" folder.

import lk_logger
from rich.markdown import Markdown

lk_logger.setup(show_varnames=True)

# -----------------------------------------------------------------------------
print(':dr', '`:e` is [yellow][u]E[/]xception[/]')

try:
    raise Exception('this is an exception with locals info')
except Exception as e:
    print(':e1', e)

# -----------------------------------------------------------------------------
print(':dr', '`:i` is [yellow][u]I[/]ndexing[/]')

print(':i', 'sunday')
print(':i', 'monday')
print(':i', 'tuesday')
print(':i', 'wednesday')
print(':i', 'thursday')
print(':i', 'friday')
print(':i', 'saturday')
print(':i0')
print(':i', 'sunday in new week')
print(':i', 'monday in new week')
print(':i', 'tuesday in new week')
print(':i', 'wednesday in new week')
print(':i', 'thursday in new week')
print(':i', 'friday in new week')
print(':i', 'saturday in new week')

# -----------------------------------------------------------------------------
print(':dr', '`:l` is [yellow][u]L[/]ong/[u]L[/]oose[/] format')

print(':l', {
    'name': 'John',
    'age': 30,
    'address': {
        'country': 'USA',
        'city': 'New York',
        'street': 'Wall Street'
    }
})

# -----------------------------------------------------------------------------
print(':dr', '`:p` is [yellow][u]P[/]arent[/] frame')


def func1():
    print('who is calling me?')
    print('i am', ':p1')
    return 'ok'


response = func1()
print(response)

# -----------------------------------------------------------------------------
print(':dr', '`:r` is [yellow][u]R[/]ich[/] format')

print(':r', '[cyan]hello[/] [yellow]world[/]')

# print a rich renderable object
print(':r1', Markdown('''
# Hello World

This is a markdown document.

- item 1
- item 2
- item 3

Find more usages at [rich](https://github.com/textualize/rich) documentation.
'''))

# automatically convert a dict to a table
print(':r2', {
    'Name': ('Alice', 'Bob', 'Charlie'),
    'Age': (18, 19, 20),
    'City': ('Shanghai', 'Beijing', 'Guangzhou'),
})

# -----------------------------------------------------------------------------
print(':dr', '`:s` [yellow][u]S[/]hort/[u]S[/]imple/[u]S[/]ingle-line[/] format')

a, b = 1, 2
print(':s', a, b, a + b)  # without varnames
print(':s1', a, b, a + b)  # similar to built-in print (but kept color style)
print(':s2', a, b, a + b)  # totally same with built-in print

# -----------------------------------------------------------------------------
print(':dr', '`:t` is [yellow][u]T[/]iming[/]')

print(':t', 'for now')

# -----------------------------------------------------------------------------
print(':dr', '`:v` is [yellow][u]V[/]erbosity[/]')

print(':v0', 'this is a TRACE message')
print(':v1', 'this is a DEBUG message')
print(':v2', 'this is a INFO  message')
print(':v3', 'this is a WARN  message')
print(':v4', 'this is a ERROR message')
print(':v5', 'this is a FATAL message')

a, b, c = 1, 2, 3
print(':v', a, b, c)

image-20240517185519671

Gallery / Code Screenshots

The projects use lk-logger to their colorful prints.

image-20240517155028545

image-20240517162243806

image-20240524071958

image-20240517190059304

More...

Markup References

A 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.

For example:

print(':i', 'monday')
print(':i', 'tuesday')
print(':i', 'wednesday')

It prints weekdays with a numeric prefix.

Here is a list of all available marks:

Mark Description
:d Divider line
:e Exception
:f Flush
:i Index
:l Long/Loose format (multiple lines)
:p Parent frame
:r Rich style
:s Short/Simple/Single-line format
:t Timestamp
:v Verbosity level

Markup options:

* d0: divider line
  d1: divider block                               *(not supported)*
* e0: exception trace back
  e1: exception trace back with showing locals
  e2: enter pdb                                   *(not supported)*
* f0: flush
  f1: flush cutoff
  f2: flush eddy               *(not a good option, maybe removed)*
  i0: reset index
* i1: update index
  i2: scoped counter
  i3: progress                                    *(not supported)*
* l0: long / loose / expanded (multiple lines)
  l1: inspect object
  p0: self layer
* p1: parent layer
  p2: grandparent layer                    *(be careful using p2+)*
  p3: great-grandparent layer
  p4: and so on...
* r0: rich style
  r1: rich object (rich.table.Table, rich.panel.Panel, etc.)
  r2: auto detect rich format (for a limit set of types)
* s0: short / simple / single line
  s1: builtin-like print (remains markup features)
  s2: builtin print
  t0: reset timer
* t1: stop timer and show statistics
  t2: temporary timer
* v0: trace / debug / hint (bright black)
  v1: info (cyan)
  v2: strong info (magenta)
  v3: weak success (green dim)
  v4: success (green)
  v5: weak warning (yellow dim)
  v6: warning (yellow)
  v7: weak error / failure (red dim)
  v8: error / failure (red)

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

lk_logger-6.0.1-py3-none-any.whl (49.8 kB view details)

Uploaded Python 3

File details

Details for the file lk_logger-6.0.1-py3-none-any.whl.

File metadata

  • Download URL: lk_logger-6.0.1-py3-none-any.whl
  • Upload date:
  • Size: 49.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.13.0 Windows/11

File hashes

Hashes for lk_logger-6.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cb5920525c8b9aa7a78a0606b469aa29b6a2ce1d234e8f7983cc98e938d226b7
MD5 9eceb283fd2c6d0df0732211ac798d2b
BLAKE2b-256 4e37c830763ccfb91a8326443a1327fe4cccd5ea879dd32861e9da2061794b59

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