Skip to main content

Make your decorators glossy!

Project description


Installation

pip install glossy

Flatter Decorators

Those who are new to python often find decorators difficult to get their head around. Glossy tries to simplify the creation of decorators by flattening the structure and reducing the number of wrapper functions required. For example:

Before:

import functools
import time


def timer(func):
    """
    Timer Decorator

    Place this decorator on functions to see
    how long they take to execute.
    """

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        return_value = func(*args, **kwargs)
        secs = time.time() - start
        name = func.__name__
        print(f"Function {name} took {secs} seconds")
        return return_value

    return wrapper

After:

import glossy
import time


@glossy.decorator
def timer(func, *args, **kwargs):
    """
    Timer

    Place this decorator on functions to see
    how long they take to execute.
    """
    start = time.time()
    result = func(*args, **kwargs)
    secs = time.time() - start
    name = func.__name__
    print(f"Function {name} took {secs} seconds")
    return result

In the first example, the top-level wrapper takes the function being decorated as input and returns a wrapper function. The inner wrapper is then responsible for calling the decorated function with the expected arguments and keyword arguments.

In the second example, we don't need multiple layers. By using the glossy.decorator utility, our decorator takes the fucntion being decorated as input and it also takes the expected arguments and keyword arguments.

Glossy works with more complex decorators too! For example:

Before:

import functools
import time


def timeout(limit=5):
    """
    Timeout

    Place this decorator on functions to raise
    an error when they exceed the given time limit.
    """

    def outer_wrapper(func):

        @functools.wraps(func)
        def inner_wrapper(*args, **kwargs):
            start = time.time()
            return_value = func(*args, **kwargs)
            duration = time.time() - start

            if duration >= timeout:
            name = func.__name__
            msg = f"Function {name} exceeded timeout: {limit}"
            raise TimeoutError(msg)

            return return_value

        return inner_wrapper

    return outer_wrapper

After:

def timeout(limit=5):
    """
    Timeout

    Place this decorator on functions to raise
    an error when they exceed the given time limit.
    """

    @decorator
    def _timeout(func, *args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        duration = time.time() - start
        if duration > limit:
            name = func.__name__
            msg = f"Function {name} exceeded timeout: {limit}"
            raise TimeoutError(msg)

        return result

    return _timeout

Inspection

The glossy library contains some handy functions for inspecting your code. For example:

import glossy

func = glossy.inspect(func)

Testing & Mocking

Regular decorators are notoriously difficult to test and/or mock. In most cases, you need to patch the decorator before you import the code that uses the decorator. This is less than ideal. Using glossy decorators, you can easily mock all decorators on a function.

@timeout(limit=1.0)
def slow(seconds):
    time.sleep(seconds)
    return True

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

glossy-0.0.1.tar.gz (7.2 kB view hashes)

Uploaded Source

Built Distribution

glossy-0.0.1-py2.py3-none-any.whl (8.1 kB view hashes)

Uploaded Python 2 Python 3

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