Uğur Özyılmazel — — Filed under development reading time: 4 minutes

fancy console logger + inspector

How do you inspect an object properties in Python? Do you have any better options than dir()? Yes you do!

vb-console is a Ruby inspired Python library. Helps two things;

  1. Use as console logger (according to you environment)
  2. Inspect objecs

You can install via pip:

$ pip install vb-console

By default, console output is disabled. You can enable output via:

  • setting ENABLE_CONSOLE environment variable
  • passing enabled=True keyword argument

Let’s try with-in the python repl:

$ ENABLE_CONSOLE=1 python

then;

>>> from console import console
>>> console = console(source='repl', enabled=True, colored=True) # enable color output!

>>> console('hello')
('hello',)

>>> d = dict(hello='world')
console(d)

({'hello':  'world'},)

If you are in a Django app, you can use;

from django.conf import settings
from console import console

# will be disabled in production!
console = console(source=__name__, enabled=settings.DEBUG)

You have few options for console output:

  • console(object)
  • console(object, object, object, ...)
  • console.dir(object)

Let’s assume that you have a class;

class MyClass:
    """Example class"""

    klass_var1 = 1
    klass_var2 = 2
    klass_var3 = 'string'
    klass_var4 = list()
    klass_var5 = dict()
    klass_var6 = set()

    def __init__(self):
        self.name = 'Name'

    def get_name_and_method(self):
        return self.name + ' get_name_and_method'

    def _private_method(self):
        return self.name + ' _private_method'

    @property
    def admin(self):
        return True

    @staticmethod
    def statik():
        return 'Static'

    @classmethod
    def klass_method(cls):
        return 'kls'

my_class_instance = MyClass()
console.dir(my_class_instance)

You’ll see:

{   'class_methods': ['klass_method'],
    'class_variables': ['klass_var1', 'klass_var2', 'klass_var3', 'klass_var4', 'klass_var5', 'klass_var6'],
    'data_attributes': ['name'],
    'internal_methods': [   '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
                            '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__',
                            '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
                            '__str__', '__subclasshook__', '__weakref__'],
    'methods': ['get_name_and_method'],
    'private_methods': ['_private_method'],
    'properties': ['admin'],
    'public_attributes': [   'admin', 'get_name_and_method', 'klass_method', 'klass_var1', 'klass_var2', 'klass_var3', 'klass_var4',
                             'klass_var5', 'klass_var6', 'name', 'statik'],
    'static_methods': ['statik']}

This is very handy, if you need to know what methods, properties are available for the given object.

You can change output style, let’s disable default output:

from console import console
console = console(source=__name__, enabled=True, basic=False) # basic is False

Outputs will contain header and footer lines. source gets it’s value from __name__ and currently the value is set to __main__:

[__main__ : instance of MyClass | <class '__main__.MyClass'>].........................................................................
{   'class_methods': ['klass_method'],
    'class_variables': ['klass_var1', 'klass_var2', 'klass_var3', 'klass_var4', 'klass_var5', 'klass_var6'],
    'data_attributes': ['name'],
    'internal_methods': [   '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
                            '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__',
                            '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
                            '__str__', '__subclasshook__', '__weakref__'],
    'methods': ['get_name_and_method'],
    'private_methods': ['_private_method'],
    'properties': ['admin'],
    'public_attributes': [   'admin', 'get_name_and_method', 'klass_method', 'klass_var1', 'klass_var2', 'klass_var3', 'klass_var4',
                             'klass_var5', 'klass_var6', 'name', 'statik'],
    'static_methods': ['statik']}
......................................................................................................................................

Current options are:

  • source: Name of the header if the basic option is set to False. It’s good idea to set to __name__
  • indent: Indentation value, default is: 4
  • width: Output’s width. Default is set to Terminal’s current width.
  • enabled: Default is False. Can be modified via ENABLE_CONSOLE env-var or setting this arg to True
  • seperator_char: Default is: .
  • colored: Default is False. Set this to True for colored output
  • dir_colors: This is a dict, default is dict(keys='yellow', values='default')
  • out_color: Default is yellow
  • header_color: Default is green
  • footer_color: Default is green
  • basic: Default is True. In basic mode, header and footer are not available
  • writer: Default is sys.stdout

Valid colors are: black, red, green, yellow, blue, magenta, cyan, white and default

Here are some examples for configuration usage:

from console import console

# colorized with header/footer
console = console(source=__name__, basic=False, colored=True)


from console import console

# custom colors without header/footer
console = console(source=__name__, colored=True, dir_colors=dict(keys='red', values='yellow'))

Quick tip; console = console(source=__name__, basic=False, colored=True) kills/overrides console from import. I mean;

>>> from console import console
>>> console = console(source=__name__, enabled=True)
>>> console('hello')
('hello',)

# now, let’s try to re-define console
>>> console = console(source=__name__, enabled=True, colored=True)
>>> console(console)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

If you want to keep console from import statement;

>>> from console import console as base_console
>>> console = base_console(source=__name__, enabled=True)
>>> console('hello')
('hello',)
>>> console = base_console(source=__name__, enabled=True, colored=True)
>>> console(console)
(<console.console.Console object at 0x10277cf40>,)
>>> console.dir([])
{   'internal_methods':  [   '__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
                            '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
                            '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__',
                            '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__',
                            '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__',
                            '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__',
                            '__setitem__', '__sizeof__', '__str__', '__subclasshook__'],
    'public_attributes':  [   'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop',
                             'remove', 'reverse', 'sort']}

Feel free to contribute!

https://github.com/vbyazilim/vb-console

Related Posts

Static Sites with mkdocs and GitHub Pages

pipx : life saver


Lastest Posts

Struct field alignment in golang

Inject values at build time

Unintended variable shadowing

Static Sites with mkdocs and GitHub Pages

Network Addresses and Named Ports