Skip to main content

A simple decorator based utility for helping with debugging

Project description

Decko

A decorator based utility module for Python developers. The module is designed to aid developers in debugging their python applications.

Decko is not dependent on any external libraries that are not included in the standard Python package. However, one may choose to extend with external libraries such as numba to improve its performance.

Decko is meant to a utility to help people debug and extend code. Its original use case is not in mission-critical fields where performance is key. If there is enough demand, I will create a separate branch which optimizes the runtime performance of all decko functions.

Updates / News

Self-contained decorators that can be used without creating a Decko instance is under development.

Install

Install and update using pip:

pip install -U decko

Uninstall

Uninstall using pip:

pip uninstall decko

Example

Decko is a decorated-based module for debugging. It also provides useful decorators to speed up programming and provides utility function for easier decorator usage. Here is an example

from decko import Decko

if __name__ == "__main__":

    dk = Decko(__name__)

    def print_list_size(size, **kwargs):
        print(f"Size of list is: {size}")

    def print_kwargs(*args, **kwargs):
        print(f"args: {args}, kwargs: {kwargs}")

    @dk.run_before([print_list_size, print_kwargs])
    @dk.profile
    def create_list(n):
        return list(range(n))

    for i in range(20):
        create_list(100000)

    # print profiled result
    dk.print_profile()

    # event triggered when original input is modified
    def catch_input_modification(arg_name, before, after):
        print(f"The argument: {arg_name} has been modified.\n"
              f"Before: {before} \n After: {after}")
        print("-" * 200)

    @dk.pure(callback=catch_input_modification)
    def create_list(n,
                    item=[]):
        item.append(n)
        return list(range(n))


    # Raise error
    for i in range(20):
        create_list(100000)

Decko also provides standalone decorators that can be applied immediately to your projects. It also has built-in decorator functions to help developers quickly build debuggable custom decorators. This allows developers to modify and extend code with minimal modifications to the existing codebase.

decorator creates function decorators that can be used to decorate both functions and classes. Demo for creating class and function decorators is shown below.

from decko import decorators.deckorator as deckorator
import time
import typing as t


def timer(func):
    """
    An ordinary decorator.
    Will be used to check the
    performance of decorate function
    """

    def inner(*args, **kwargs):
        start_time = time.time()
        output = func(*args, **kwargs)
        elapsed = time.time() - start_time
        print(f"Time elapsed: {elapsed}")
        return output

    return inner

# Create decorator called "time_it" that accepts the following args
# 1. Int value
# 2. A callable object or a List
@deckorator((int, float), (t.Callable, t.List))
def time_it(wrapped_function,
            interval,
            callback,
            *args, **kwargs):
    print(f"wrapped function: {wrapped_function.__name__}, interval: {interval},"
          f" args: {args}")
    # Check every 5 interval
    i = time_it.called
    if (i + 1) % interval == 0:
        start_time = time.time()
        output = wrapped_function(*args, **kwargs)
        elapsed = time.time() - start_time
        callback(elapsed, i + 1)
    else:
        output = wrapped_function(*args, **kwargs)
    time_it.called += 1
    return output


time_it.called = 0


@deckorator
def immutable(wrapped_class,
              *args,
              **kwargs):

    def do_freeze(slf, name, value):
        msg = f"Class {type(slf)} is immutable. " \
              f"Attempted to set attribute '{name}' to value: '{value}'"
        raise AttributeError(msg)

    class Immutable(wrapped_class):
        """
        A basic immutable class
        """
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            setattr(Immutable, '__setattr__', do_freeze)

    return Immutable(*args, **kwargs)


@immutable
class SampleClass:
    def __init__(self, a, teemo):
        self.a = a

    @time_it(1, print)
    @classmethod
    def method(cls):
        return "yee"


if __name__ == "__main__":
    # for i in range(10):
    #     long_list(10000000, i)

    deco_cls = SampleClass(10, 20)
    deco_cls.method()
    test = SampleClass(20, 40)
    try:
        deco_cls.a = 50
    except AttributeError:
        print("class is immutable")
    print(deco_cls.a)

Features

Decko detects and raises customized, informative errors such as DuplicateDecoratorError. This helps in debugging and extending features with minimal modifications to the existing codebase.

from decko import Decko

dk = Decko(__name__, debug=True)


def log_impurity(argument, before, after):
    print(f"Argument: {argument} modified. Before: {before}, after: {after}")


def i_run_before(a, b, c, item):
    print(f"Run before func: {a}, {b}, {c}, {item}")


@dk.run_before(i_run_before)    # This should not be allowed since it is a duplicate
@dk.run_before(i_run_before)  
@dk.pure(callback=log_impurity)
@dk.profile
def expensive_func(a,
                   b,
                   c=1000000,
                   item=[]):
    for i in range(100):
        temp_list = list(range(c))
        item.append(temp_list)

    a += 20
    b += a
    total = a + b
    return total


class DummyClass:
    def __init__(self, item):
        self.item = item

    # @dk.pure(log_impurity)
    # @dk.profile
    def set_item(self, item):
        self.item = item

    def __repr__(self):
        return f'DummyClass: {self.item}'


test = DummyClass(10)
test.set_item(20)

# Error raised
output = expensive_func(10, 20, 40)

Decko raises informative error messages to help debug issues. In later versions, features to define error callbacks with custom exceptions will be made.

Traceback (most recent call last):
  File "path", line 17, in <module>
    def expensive_func(a,
  File "path", line 522, in wrapper
    fn: t.Callable = self._decorate(self.run_before, fn)
  File "path", line 334, in _decorate
    self.add_decorator_rule(decorator_func, func)
  File "path", line 241, in add_decorator_rule
    self._add_function_decorator_rule(decorator_func,
  File "path", line 213, in _add_function_decorator_rule
    self._update_decoration_info(decorator_func, func, properties)
  File "path", line 490, in _update_decoration_info
    self.handle_error(f"Found duplicate decorator with identity: {func_name}",
  File "path", line 325, in handle_error
    raise error_type(msg)
src.decko.exceptions.DuplicateDecoratorError: Found duplicate decorator with identity: __main__.expensive_func

Links

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

decko-0.0.2.3.tar.gz (22.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

decko-0.0.2.3-py3-none-any.whl (23.2 kB view details)

Uploaded Python 3

File details

Details for the file decko-0.0.2.3.tar.gz.

File metadata

  • Download URL: decko-0.0.2.3.tar.gz
  • Upload date:
  • Size: 22.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/3.7.3 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.59.0 CPython/3.8.8

File hashes

Hashes for decko-0.0.2.3.tar.gz
Algorithm Hash digest
SHA256 f866aa5a45d1dfa90052ace377aacbeac7c11ab9aa01dc3edd2326a38587aa9f
MD5 f36cc28d8a11165b18ff8d8c8e7b58ce
BLAKE2b-256 4ffa5a45e7c8d8f1a720245cba75041cc2dc8c63d916a47be4ff2cd0dffd9359

See more details on using hashes here.

File details

Details for the file decko-0.0.2.3-py3-none-any.whl.

File metadata

  • Download URL: decko-0.0.2.3-py3-none-any.whl
  • Upload date:
  • Size: 23.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/3.7.3 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.59.0 CPython/3.8.8

File hashes

Hashes for decko-0.0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 92f5585ec60459eda2fb221103ceb28028eb796e8f4952556c92906225de5907
MD5 7414eb39328b1273a1c0f196f2c7495a
BLAKE2b-256 ce5f4e7fb093c5875b561ff1d7dfe1093c1f9583062c0cd5929bf7a2c4cd1c88

See more details on using hashes here.

Supported by

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