python 一个装饰器,通过地狱放置功能,所以在生产中你的代码已经看到更糟糕了。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 一个装饰器,通过地狱放置功能,所以在生产中你的代码已经看到更糟糕了。相关的知识,希望对你有一定的参考价值。

# -*- coding: utf-8 -*-
# @Author: Cody Kochmann
# @Date:   2017-04-26 11:41:19
# @Last Modified by:   Cody L. Kochmann
# @Last Modified time: 2017-04-26 18:25:01
from functools import wraps
import logging
import better_exceptions
from hypothesis import given, strategies as st, settings, Verbosity

garbage = (
    st.binary(),
    st.booleans(),
    st.characters(),
    st.complex_numbers(),
    st.decimals(),
    st.floats(),
    st.fractions(),
    st.integers(),
    st.none(),
    st.random_module(),
    st.randoms(),
    st.text(),
    st.tuples(),
    st.uuids()
)
garbage+=(
    st.lists(elements=st.one_of(*garbage)),
    st.iterables(elements=st.one_of(*garbage))
)
garbage=st.one_of(*garbage)


def function_args(fn):
    """ generates a list of the given function's arguments
        by: Cody Kochmann """
    assert callable(fn), 'function_args needed a callable function, not {0}'.format(repr(fn))
    try: # python2 implementation
        from inspect import getargspec
        return getargspec(fn).args
    except: # python3 implementation
        from inspect import signature
        return signature(fn).parameters

class battle_tested(object):
    """ A decorator that puts functions through hell so in production your code
        will have already seen worse.

        by: Cody Kochmann
    """

    def __init__(self, timeout=1, max_examples=1000000, verbose=False, **kwargs):
        """ your general constructor to get things in line """
        self.kwargs = kwargs
        self.tested = False
        self.verbosity = (Verbosity.verbose if verbose else Verbosity.normal)
        assert type(timeout) == int, 'battle_tested needs timeout to be an int, not {}'.format(repr(timeout))
        self.timeout = timeout
        assert type(max_examples) == int, 'battle_tested needs max_examples to be an int, not {}'.format(repr(max_examples))
        self.max_examples = max_examples

    def battle_test(self,fn):
        """ where the function is actually battle tested """
        # get number of args this function needs
        args_needed=len(function_args(fn))
        # generate a strategy that creates a list of garbage variables for each argument
        strategy = st.lists(elements=garbage, max_size=args_needed, min_size=args_needed)

        @settings(timeout=self.timeout,max_examples=self.max_examples,verbosity=self.verbosity)
        @given(strategy)
        def test(arg_list):
            # unpack the arguments
            fn(*arg_list)
        # run the test
        test()

    def __call__(self, fn):
        """ runs before the decorated function is called """
        assert callable(fn), "battle_tested needs a callable target to wrap"

        if not self.tested:
            print 'testing:', fn.__name__
            # only test the first time this function is called
            if not ('skip_test' in self.kwargs and self.kwargs['skip_test']):
                # skip the test if it is explicitly turned off
                self.battle_test(fn)
            self.tested = True
        else:
            print 'already tested:',fn.__name__

        def wrapper(*args, **kwargs):
            try:
                out = fn(*args, **kwargs)
            except Exception as e:
                # log the error
                if 'logger' in self.kwargs:
                    assert callable(self.kwargs['logger']), "battle_tested.logger needs to be a callable log function, not: {}".format(repr(self.kwargs['logger']))
                    self.kwargs['logger'](e)
                else:
                    logging.exception(e)
                # only raise the error if there isnt a default_output
                if 'default_output' in self.kwargs:
                    out = self.kwargs['default_output']
                else:
                    raise e
            return out
        return wrapper

if __name__ == '__main__':
    @battle_tested(default_output=[])
    def sample(i):
        return []

    @battle_tested(default_output=[])
    def sample2(i):
        return []


    @battle_tested(default_output=[])
    def sample23(a,b):
        return []

    print sample(4)
    print sample2(4)
    print sample(4)
    print sample2(4)
    print('finished running battle_tested.py')

以上是关于python 一个装饰器,通过地狱放置功能,所以在生产中你的代码已经看到更糟糕了。的主要内容,如果未能解决你的问题,请参考以下文章

Python-装饰器

Python装饰器

python装饰器

python装饰器了解

Python自动化开发学习4-装饰器

Python自动化开发学习4-装饰器