functools.wraps

Here are the examples of the python api functools.wraps taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

200 Examples 7

Example 1

Project: dose
Source File: compat.py
View license
def _wx_two_step_creation_on_classic(cls):
    """
    Patch the wxPython Classic class to behave like a wxPython
    Phoenix class on a 2-step creation process.

    On wxPython Phoenix, the first step is the parameterless
    ``__init__``, and the second step is the ``Create`` method with
    the construction parameters, e.g.::

        class CustomFrame(wx.Frame):
            def __init__(self, parent):
                super(CustomFrame, self).__init__() # 1st step
                # [...]
                self.Create(parent) # 2nd step
                # [...]

    On wxPython Classic, the same would be written as::

        class CustomFrame(wx.Frame):
            def __init__(self, parent):
                pre = wx.PreFrame() # 1st step
                # [... using "pre" instead of "self" ...]
                pre.Create(parent) # 2nd step
                self.PostCreate(pre) # "3rd step"
                # [...]
    """
    cls_init = cls.__init__
    cls_create = cls.Create

    @functools.wraps(cls_init)
    def __init__(self, *args, **kwargs):
        if args or kwargs:
            cls_init(self, *args, **kwargs)
        else: # 2-step creation
            new_self = getattr(wx, "Pre" + cls.__name__)()
            for pair in vars(new_self).items():
                setattr(self, *pair)

    if sys.platform == "win32":
        # On Windows, the wx.Pre*.Create constructors calls the
        # EVT_WINDOW_CREATE handler before returning (i.e, it processes
        # the event instead of just adding a message to the queue), and
        # that shouldn't happen before the PostCreate call in this thread
        @functools.wraps(cls_create)
        def create(self, *args, **kwargs):
            self.SetEvtHandlerEnabled(False)
            result = cls_create(self, *args, **kwargs)
            self.SetEvtHandlerEnabled(True)
            if result:
                self.PostCreate(self)
                wx.PostEvent(self, wx.WindowCreateEvent(self))
            return result
    else:
        @functools.wraps(cls_create)
        def create(self, *args, **kwargs):
            result = cls_create(self, *args, **kwargs)
            if result:
                self.PostCreate(self)
            return result

    cls.__init__ = __init__
    cls.Create = create

Example 2

Project: lrrbot
Source File: utils.py
View license
def coro_decorator(decorator):
	"""
	Utility decorator used when defining other decorators, so they can wrap
	either normal functions or asyncio coroutines.

	Usage:
	@coro_decorator
	def decorator(func):
		@functools.wraps(func)
		@asyncio.coroutine # decorator must return a coroutine, and use "yield from" to call func
		def wrapper(...)
			...
			ret = yield from func(...)
			...
			return ...
		return wrapper

	@decorator
	def normal_func():
		pass

	@decorator # @decorator must be above @coroutine
	@asyncio.coroutine
	def coro_func():
		pass

	Note that the decorator must *not* yield from anything *except* the function
	it's decorating.
	"""
	# any extra properties that we want to assign to wrappers, in any of the decorators
	# we use this on
	EXTRA_PARAMS = ('reset_throttle',)
	@functools.wraps(decorator)
	def wrapper(func):
		is_coro = asyncio.iscoroutinefunction(func)
		if not is_coro:
			func = asyncio.coroutine(func)

		decorated_coro = decorator(func)
		assert asyncio.iscoroutinefunction(decorated_coro)

		if is_coro:
			return decorated_coro
		else:
			# Unwrap the coroutine. We know it should never yield.
			@functools.wraps(decorated_coro, assigned=functools.WRAPPER_ASSIGNMENTS + EXTRA_PARAMS, updated=())
			def decorated_func(*args, **kwargs):
				x = iter(decorated_coro(*args, **kwargs))
				try:
					next(x)
				except StopIteration as e:
					return e.value
				else:
					raise Exception("Decorator %s behaving badly wrapping non-coroutine %s" % (decorator.__name__, func.__name__))
			return decorated_func
	return wrapper

Example 3

Project: lrrbot
Source File: utils.py
View license
def coro_decorator(decorator):
	"""
	Utility decorator used when defining other decorators, so they can wrap
	either normal functions or asyncio coroutines.

	Usage:
	@coro_decorator
	def decorator(func):
		@functools.wraps(func)
		@asyncio.coroutine # decorator must return a coroutine, and use "yield from" to call func
		def wrapper(...)
			...
			ret = yield from func(...)
			...
			return ...
		return wrapper

	@decorator
	def normal_func():
		pass

	@decorator # @decorator must be above @coroutine
	@asyncio.coroutine
	def coro_func():
		pass

	Note that the decorator must *not* yield from anything *except* the function
	it's decorating.
	"""
	# any extra properties that we want to assign to wrappers, in any of the decorators
	# we use this on
	EXTRA_PARAMS = ('reset_throttle',)
	@functools.wraps(decorator)
	def wrapper(func):
		is_coro = asyncio.iscoroutinefunction(func)
		if not is_coro:
			func = asyncio.coroutine(func)

		decorated_coro = decorator(func)
		assert asyncio.iscoroutinefunction(decorated_coro)

		if is_coro:
			return decorated_coro
		else:
			# Unwrap the coroutine. We know it should never yield.
			@functools.wraps(decorated_coro, assigned=functools.WRAPPER_ASSIGNMENTS + EXTRA_PARAMS, updated=())
			def decorated_func(*args, **kwargs):
				x = iter(decorated_coro(*args, **kwargs))
				try:
					next(x)
				except StopIteration as e:
					return e.value
				else:
					raise Exception("Decorator %s behaving badly wrapping non-coroutine %s" % (decorator.__name__, func.__name__))
			return decorated_func
	return wrapper

Example 4

Project: premailer
Source File: cache.py
View license
def function_cache(expected_max_entries=1000):
    """
        function_cache is a decorator for caching function call
        the argument to the wrapped function must be hashable else
        it will not work

        expected_max_entries is for protecting cache failure. If cache
        misses more than this number the cache will turn off itself.
        Specify None you sure that the cache  will not cause memory
        limit problem.

        Args:
            expected_max_entries(integer OR None): will raise if not correct

        Returns:
            function

    """
    if (
        expected_max_entries is not None and
        not isinstance(expected_max_entries, int)
    ):
        raise TypeError(
            'Expected expected_max_entries to be an integer or None'
        )

    # indicator of cache missed
    sentinel = object()

    def decorator(func):
        cached = _Cache()

        @functools.wraps(func)
        def inner(*args, **kwargs):
            if cached.off:
                return func(*args, **kwargs)

            keys = args
            if kwargs:
                sorted_items = sorted(kwargs.items())
                for item in sorted_items:
                    keys += item

            hashed = hash(_HashedSeq(keys))
            result = cached.cache.get(hashed, sentinel)
            if result is sentinel:
                cached.missed += 1
                result = func(*args, **kwargs)
                cached.cache[hashed] = result
                # # something is wrong if we are here more than expected
                # # empty and turn it off
                if (
                    expected_max_entries is not None and
                    cached.missed > expected_max_entries
                ):
                    cached.off = True
                    cached.cache.clear()

            return result

        return inner
    return decorator

Example 5

Project: chainer
Source File: condition.py
View license
def repeat_with_success_at_least(times, min_success):
    """Decorator for multiple trial of the test case.

    The decorated test case is launched multiple times.
    The case is judged as passed at least specified number of trials.
    If the number of successful trials exceeds `min_success`,
    the remaining trials are skipped.

    Args:
        times(int): The number of trials.
        min_success(int): Threshold that the decorated test
            case is regarded as passed.

    """

    assert times >= min_success

    def _repeat_with_success_at_least(f):
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            assert len(args) > 0
            instance = args[0]
            assert isinstance(instance, unittest.TestCase)
            success_counter = 0
            failure_counter = 0
            results = []

            def fail():
                msg = '\nFail: {0}, Success: {1}'.format(
                    failure_counter, success_counter)
                if len(results) > 0:
                    first = results[0]
                    errs = first.failures + first.errors
                    if len(errs) > 0:
                        err_msg = '\n'.join(fail[1] for fail in errs)
                        msg += '\n\nThe first error message:\n' + err_msg
                instance.fail(msg)

            for _ in six.moves.range(times):
                suite = unittest.TestSuite()
                suite.addTest(
                    unittest.FunctionTestCase(
                        lambda: f(*args, **kwargs),
                        setUp=instance.setUp,
                        tearDown=instance.tearDown))

                result = QuietTestRunner().run(suite)
                if result.wasSuccessful():
                    success_counter += 1
                else:
                    results.append(result)
                    failure_counter += 1
                if success_counter >= min_success:
                    instance.assertTrue(True)
                    return
                if failure_counter > times - min_success:
                    fail()
                    return
            fail()
        return wrapper
    return _repeat_with_success_at_least

Example 6

Project: chainer
Source File: helper.py
View license
def for_dtypes_combination(types, names=('dtype',), full=None):
    """Decorator that checks the fixture with a product set of dtypes.

    Args:
         types(list of dtypes): dtypes to be tested.
         names(list of str): Argument names to which dtypes are passed.
         full(bool): If ``True``, then all combinations
             of dtypes will be tested.
             Otherwise, the subset of combinations will be tested
             (see the description below).

    Decorator adds the keyword arguments specified by ``names``
    to the test fixture. Then, it runs the fixtures in parallel
    with passing (possibly a subset of) the product set of dtypes.
    The range of dtypes is specified by ``types``.

    The combination of dtypes to be tested changes depending
    on the option ``full``. If ``full`` is ``True``,
    all combinations of ``types`` are tested.
    Sometimes, such an exhaustive test can be costly.
    So, if ``full`` is ``False``, only the subset of possible
    combinations is tested. Specifically, at first,
    the shuffled lists of ``types`` are made for each argument
    name in ``names``.
    Let the lists be ``D1``, ``D2``, ..., ``Dn``
    where :math:`n` is the number of arguments.
    Then, the combinations to be tested will be ``zip(D1, ..., Dn)``.
    If ``full`` is ``None``, the behavior is switched
    by setting the environment variable ``CUPY_TEST_FULL_COMBINATION=1``.

    For example, let ``types`` be ``[float16, float32, float64]``
    and ``names`` be ``['a_type', 'b_type']``. If ``full`` is ``True``,
    then the decorated test fixture is executed with all
    :math:`2^3` patterns. On the other hand, if ``full`` is ``False``,
    shuffled lists are made for ``a_type`` and ``b_type``.
    Suppose the lists are ``(16, 64, 32)`` for ``a_type`` and
    ``(32, 64, 16)`` for ``b_type`` (prefixes are removed for short).
    Then the combinations of ``(a_type, b_type)`` to be tested are
    ``(16, 32)``, ``(64, 64)`` and ``(32, 16)``.
    """

    if full is None:
        full = int(os.environ.get('CUPY_TEST_FULL_COMBINATION', '0')) != 0

    if full:
        combination = parameterized.product({name: types for name in names})
    else:
        ts = []
        for _ in range(len(names)):
            # Make shuffled list of types for each name
            t = list(types)
            random.shuffle(t)
            ts.append(t)

        combination = [dict(zip(names, typs)) for typs in zip(*ts)]

    def decorator(impl):
        @functools.wraps(impl)
        def test_func(self, *args, **kw):
            for dtypes in combination:
                kw_copy = kw.copy()
                kw_copy.update(dtypes)

                try:
                    impl(self, *args, **kw_copy)
                except Exception:
                    print(dtypes)
                    raise

        return test_func
    return decorator

Example 7

Project: cupy
Source File: condition.py
View license
def repeat_with_success_at_least(times, min_success):
    """Decorator for multiple trial of the test case.

    The decorated test case is launched multiple times.
    The case is judged as passed at least specified number of trials.
    If the number of successful trials exceeds `min_success`,
    the remaining trials are skipped.

    Args:
        times(int): The number of trials.
        min_success(int): Threshold that the decorated test
            case is regarded as passed.

    """

    assert times >= min_success

    def _repeat_with_success_at_least(f):
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            assert len(args) > 0
            instance = args[0]
            assert isinstance(instance, unittest.TestCase)
            success_counter = 0
            failure_counter = 0
            results = []

            def fail():
                msg = '\nFail: {0}, Success: {1}'.format(
                    failure_counter, success_counter)
                if len(results) > 0:
                    first = results[0]
                    errs = first.failures + first.errors
                    if len(errs) > 0:
                        err_msg = '\n'.join(fail[1] for fail in errs)
                        msg += '\n\nThe first error message:\n' + err_msg
                instance.fail(msg)

            for _ in six.moves.range(times):
                suite = unittest.TestSuite()
                suite.addTest(
                    unittest.FunctionTestCase(
                        lambda: f(*args, **kwargs),
                        setUp=instance.setUp,
                        tearDown=instance.tearDown))

                result = QuietTestRunner().run(suite)
                if result.wasSuccessful():
                    success_counter += 1
                else:
                    results.append(result)
                    failure_counter += 1
                if success_counter >= min_success:
                    instance.assertTrue(True)
                    return
                if failure_counter > times - min_success:
                    fail()
                    return
            fail()
        return wrapper
    return _repeat_with_success_at_least

Example 8

Project: cupy
Source File: helper.py
View license
def for_dtypes_combination(types, names=('dtype',), full=None):
    """Decorator that checks the fixture with a product set of dtypes.

    Args:
         types(list of dtypes): dtypes to be tested.
         names(list of str): Argument names to which dtypes are passed.
         full(bool): If ``True``, then all combinations
             of dtypes will be tested.
             Otherwise, the subset of combinations will be tested
             (see the description below).

    Decorator adds the keyword arguments specified by ``names``
    to the test fixture. Then, it runs the fixtures in parallel
    with passing (possibly a subset of) the product set of dtypes.
    The range of dtypes is specified by ``types``.

    The combination of dtypes to be tested changes depending
    on the option ``full``. If ``full`` is ``True``,
    all combinations of ``types`` are tested.
    Sometimes, such an exhaustive test can be costly.
    So, if ``full`` is ``False``, only the subset of possible
    combinations is tested. Specifically, at first,
    the shuffled lists of ``types`` are made for each argument
    name in ``names``.
    Let the lists be ``D1``, ``D2``, ..., ``Dn``
    where :math:`n` is the number of arguments.
    Then, the combinations to be tested will be ``zip(D1, ..., Dn)``.
    If ``full`` is ``None``, the behavior is switched
    by setting the environment variable ``CUPY_TEST_FULL_COMBINATION=1``.

    For example, let ``types`` be ``[float16, float32, float64]``
    and ``names`` be ``['a_type', 'b_type']``. If ``full`` is ``True``,
    then the decorated test fixture is executed with all
    :math:`2^3` patterns. On the other hand, if ``full`` is ``False``,
    shuffled lists are made for ``a_type`` and ``b_type``.
    Suppose the lists are ``(16, 64, 32)`` for ``a_type`` and
    ``(32, 64, 16)`` for ``b_type`` (prefixes are removed for short).
    Then the combinations of ``(a_type, b_type)`` to be tested are
    ``(16, 32)``, ``(64, 64)`` and ``(32, 16)``.
    """

    if full is None:
        full = int(os.environ.get('CUPY_TEST_FULL_COMBINATION', '0')) != 0

    if full:
        combination = parameterized.product({name: types for name in names})
    else:
        ts = []
        for _ in range(len(names)):
            # Make shuffled list of types for each name
            t = list(types)
            random.shuffle(t)
            ts.append(t)

        combination = [dict(zip(names, typs)) for typs in zip(*ts)]

    def decorator(impl):
        @functools.wraps(impl)
        def test_func(self, *args, **kw):
            for dtypes in combination:
                kw_copy = kw.copy()
                kw_copy.update(dtypes)

                try:
                    impl(self, *args, **kw_copy)
                except Exception:
                    print(dtypes)
                    raise

        return test_func
    return decorator

Example 9

Project: pika
Source File: test_utils.py
View license
def retry_assertion(timeout_sec, retry_interval_sec=0.1):
    """Creates a decorator that retries the decorated function or
    method only upon `AssertionError` exception at the given retry interval
    not to exceed the overall given timeout.

    :param float timeout_sec: overall timeout in seconds
    :param float retry_interval_sec: amount of time to sleep
        between retries in seconds.

    :returns: decorator that implements the following behavior

    1. This decorator guarantees to call the decorated function or method at
    least once.
    2. It passes through all exceptions besides `AssertionError`, preserving the
    original exception and its traceback.
    3. If no exception, it returns the return value from the decorated function/method.
    4. It sleeps `time.sleep(retry_interval_sec)` between retries.
    5. It checks for expiry of the overall timeout before sleeping.
    6. If the overall timeout is exceeded, it re-raises the latest `AssertionError`,
    preserving its original traceback
    """

    def retry_assertion_decorator(func):
        """Decorator"""

        @functools.wraps(func)
        def retry_assertion_wrap(*args, **kwargs):
            """The wrapper"""

            num_attempts = 0
            start_time = time.time()

            while True:
                num_attempts += 1

                try:
                    result = func(*args, **kwargs)
                except AssertionError:

                    now = time.time()
                    # Compensate for time adjustment
                    if now < start_time:
                        start_time = now

                    if (now - start_time) > timeout_sec:
                        logging.exception(
                            'Exceeded retry timeout of %s sec in %s attempts '
                            'with func %r. Caller\'s stack:\n%s',
                            timeout_sec, num_attempts, func,
                            ''.join(traceback.format_stack()))
                        raise

                    logging.debug('Attempt %s failed; retrying %r in %s sec.',
                                  num_attempts, func, retry_interval_sec)

                    time.sleep(retry_interval_sec)
                else:
                    logging.debug('%r succeeded at attempt %s',
                                  func, num_attempts)
                    return result

        return retry_assertion_wrap

    return retry_assertion_decorator

Example 10

Project: kingpin
Source File: thrift_client_mixin.py
View license
    def __new__(mcs, classname, bases, classdict):
        # We assume thrift-client class is the first base of the subclass
        # of PooledThriftClientMixin.
        _thrift_client_cls = bases[0]

        # The following two functions are meant to be injected into
        # the created subclass of PooledThriftClientMixin as its
        # member functions.
        def _ensure_use_pooled_client(self, method, timeout=5000,
                                      expiration=5000, e2e_timeout=5000):
            """Ensure a call is made exclusively on a client in the connection
            pool.

            Args:
                method: a method from a thrift-client class.
                timeout: the maximum time (ms) to wait for a connection.
                expiration: the maximum time (ms) the method may execute using
                    a connection before an exception may be raised.
                e2e_timeout: the end-to-end timeout (ms), including both the
                    time spent on acquire the connection and rpc, and all the
                    retries if there is any.

            Returns:
                a wrapped version of method that grabs a client from the pool
                and uses the client to perform the method.

            """
            @functools.wraps(method)
            def wrap_with_pool(*args, **kwargs):
                if self.client_pool.qsize() == 0:
                    log.info("Contention on thrift-pool %s. Empty pool." %
                             self.client_pool.pool_name)
                with self.client_pool.get_connection(
                        timeout=timeout / MILLIS_PER_SEC,
                        expiration=expiration / MILLIS_PER_SEC,
                        replace_if=self.conn_replace_policy,
                        e2e_timeout=e2e_timeout / MILLIS_PER_SEC) as client:
                    return method(client, *args, **kwargs)

            return wrap_with_pool

        def __init__(self, host_provider, pool_size=5, timeout=5000,
                     retry_policy=None, connection_wait_timeout=5000,
                     connection_expiration=5000, statsd_client=dummy_statsd,
                     socket_connection_timeout=None,
                     always_retry_on_new_host=False,
                     retry_count=3,
                     conn_replace_policy=default_thrift_client_replace_if,
                     protocol_factory=DEFAULT_THRIFT_PROTOCOL_FACTORY,
                     e2e_timeout=5000,
                     is_ssl=False, validate=True, ca_certs=None,
                     failed_retry_policy_log_sample_rate=1.0):
            """Constructor for PooledThriftClientMixin's subclass.

            The five timeout parameters interact in the following way:

                1. Wait 'connection_wait_timeout' to acquire a connection from
                   the pool. If timeout, give up and raise an exception (most
                   likely gevent.queue.Empty).

                2. Once a connection is acquired, the number of milliseconds
                   specified by 'connection_expiration' is available for the
                   connection, including all retries.  If more time elapses,
                   a services.utils.connection_pool.ExpiredConnection exception
                   is raised.

                3. If the underlying connection needs to be established for
                   first time, we will only wait up to
                   ``socket_connection_timeout``, if connection timeout
                   happens, we will get socket error, and the retry
                   mechanism will start to kick in. By default, it is None,
                   which will fallback to timeout specified.

                4. If the RPC fails or takes more than 'timeout' milliseconds
                   and the 'connection_expiration' limit has not been eached,
                   the RPC will be retried up to three times.

                5. ``e2e_timeout`` is the end-to-end timeout setting that take
                    both ``connection_wait_timeout`` and
                    ``connection_expiration``. If you only want to specify one
                    timeout on your client, specify this one.

            In general, the ExpiredConnection exception should not be caught in
            the context of retry logic. The exception is meant to be used as
            the last resort to prevent connection leaks caused by clients
            holding the connection forever.

            If the desired behavior is to guarantee time for all retries, the
            recommended client strategy is to set 'connection_expiration' to at
            least 'timeout' multiplied by the number of retries allowed (3).

            Args:
                host_provider: a HostProvider object to that provide a list of
                available "host:port".
                pool_size: max number of clients in the pool.
                socket_connection_timeout: the socket timeout (ms) for
                    establishing the underlying socket connection for the
                    first time.
                timeout: the socket timeout (ms) passed ot the connection pool.
                retry_policy: an instance of RetryPolicy. It should have a
                    function 'should_retry' that takes an exception as argument
                    and return a boolean value indicating whether the RPC
                    should be retried. See RetryPolicy in retry_policy.py for
                    the default retry policy.
                connection_wait_timeout: the maximum time (ms) to wait for a
                    connection to become available in the connection pool.
                connection_expiration: the maximum time (ms) a connection is
                    allowed to be out of the connection pool.
                statsd_client: a statsd client to report stats.
                socket_connection_timeout: timeout when connecting to a thrift
                    server.
                always_retry_on_new_host: whether to always retry on a new host.
                    By default, only the last retry is on a new host.
                retry_count: total number of attempts before fail a request.
                conn_replace_policy: a function that takes one argument which
                    is an exception and return a boolean indicating whether
                    to discard the connection for the exception. By default,
                    a connection is discarded for all exceptions other than user
                    defined thrift exceptions.
                protocol_factory: thrift protocol factory.
                e2e_timeout: end-to-end timeout in milliseconds. It includes
                    time taken for establishing connection, retries if
                    necessary, etc. If you only specify one timeout on your
                    client, this is the one you should specify.
                is_ssl: use SSL connection or not, default is False.
                validate: Set to False to disable SSL certificate validation.
                ca_certs: Filename to the Certificate Authority pem file.
                failed_retry_policy_log_sample_rate: sometimes the "failed retry policy
                    becomes too overwhelming so you can set a logging
                    sample rate which ranges from [0, 1.0].

            """
            # This is the mixin class for the objects we create in the pool.
            class _ThriftClientMixinClass(_thrift_client_cls,
                                          ThriftClientMixin):
                # noinspection PyMethodParameters
                def get_connection_exception_class(mixin_self):
                    return self.get_connection_exception_class()

            def _close_conn(client):
                """Close the socket maintained by the client."""
                client.teardown_connection()

            # For every method in _ThriftClientMixinClass, create a
            # corresponding method with the same name but work with the client
            # in the pool.
            for method_name, method in getmembers(_ThriftClientMixinClass,
                                                  predicate=ismethod):
                # Ignore private methods.
                if method_name[0][0] == '_':
                    continue

                # Ignore methods not in _thrift_client_cls.
                client_attr = getattr(_thrift_client_cls, method_name, None)
                if client_attr is None or not ismethod(client_attr):
                    continue

                # Create delegating method in self for method in
                # _ThriftClientMixinClass (whose methods are the same as
                # those in _thrift_client_cls.)
                #
                # Note the created self.method_name is *not* bound
                # to self when it's invoked. It's an unbound method
                # from _ThriftClientMixinClass decorated by
                # _ensure_use_pooled_client() which bounds 'method' with a
                # client from the pool.
                setattr(self, method_name,
                        self._ensure_use_pooled_client(
                            method,
                            timeout=connection_wait_timeout,
                            expiration=connection_expiration,
                            e2e_timeout=e2e_timeout))

            # Pool name
            pool_name = "%s.%s" % (_thrift_client_cls.__module__,
                                   _thrift_client_cls.__name__)
            # The pool that contains non-greenlet-safe mixin clients.
            self.client_pool = ConnectionPool(
                pool_name=pool_name,
                pool_size=pool_size,
                close_conn_f=_close_conn,
                conn_cls=_ThriftClientMixinClass,
                host_provider=host_provider,
                timeout=timeout,
                statsd_client=statsd_client,
                retry_policy=retry_policy,
                socket_connection_timeout=socket_connection_timeout,
                always_retry_on_new_host=always_retry_on_new_host,
                retry_count=retry_count,
                protocol_factory=protocol_factory,
                is_ssl=is_ssl,
                validate=validate,
                ca_certs=ca_certs,
                failed_retry_policy_log_sample_rate=failed_retry_policy_log_sample_rate)

            # Function that decide whether to discard a connection when
            # exception happens.
            self.conn_replace_policy = conn_replace_policy

        # Inject the two member functions in PooledThriftClientMixin's
        # subclass.
        classdict['_ensure_use_pooled_client'] = _ensure_use_pooled_client
        classdict['__init__'] = __init__

        return super(PooledThriftClientMixinMetaclass, mcs).__new__(
            mcs, classname, bases, classdict)

Example 11

Project: kingpin
Source File: thrift_client_mixin.py
View license
def ensure_connection(service_name, method_name, method):
    """Ensure that client is connected before executing method.

    .. note:: Class to which this decorator is applied **must** have
       ``get_connection_exception_class()`` method that would return the
       class of the exception to be thrown when retryable connection
       exception is repacked.

    This decorator can only be applied to class methods,
    not a non-class function.

    Args:
        method_name: A string, the name of the method to be ensured.
        method: A string, the actual method to be ensured.

    Returns:
        Whatever the executed method returns.

    """
    @functools.wraps(method)
    def method_wrapper(self, *args, **kwargs):

        req_timeout_ms = kwargs.pop('rpc_timeout_ms', self.timeout)
        conn_timeout_ms = kwargs.pop('rpc_timeout_ms',
                                     self.socket_connection_timeout)
        if conn_timeout_ms is None:
            conn_timeout_ms = req_timeout_ms
        retries_left = self.retry_count
        while retries_left:
            start_time = datetime.datetime.now()
            try:
                # Ensure connection.
                try:
                    self.connect(conn_timeout_ms, req_timeout_ms)
                except socket.timeout:
                    raise ThriftConnectionTimeoutError()
                result = method(self._client, *args, **kwargs)
                time_taken = datetime.datetime.now() - start_time
                # compute time taken into milliseconds
                time_taken_ms = time_taken.total_seconds() * 1000
                self.statsd_client.timing(
                    "client.requests.{0}.{1}".format(service_name, method_name),
                    time_taken_ms, sample_rate=0.001)
                self.refresh_connection_if_needed()
                return result
            except TApplicationException as e:
                handler_args = args_to_str(*args, **kwargs)
                time_taken = datetime.datetime.now() - start_time
                # compute time taken into milliseconds
                time_taken_ms = time_taken.total_seconds() * 1000
                log.info(
                    "Thrift call failed TApplicationException : %s(%s) : "
                    "%s:%d : time_taken_ms : %s : %s" % (
                        method_name, handler_args, self.host,
                        self.port, time_taken_ms, e))
                raise
            except Exception as e:
                t, v, tb = sys.exc_info()
                retries_left -= 1
                handler_args = args_to_str(*args, **kwargs)
                time_taken = datetime.datetime.now() - start_time
                # compute time taken into milliseconds
                time_taken_ms = time_taken.total_seconds() * 1000

                # application exception, if it is retriable as determined by
                # RetryPolicy then we simply raise the exception, no connection
                # teardown is needed, because the exception was thrown by the
                # server and transported back to the client.
                if _is_application_exception(e):
                    retry_policy_to_apply = self.retry_policy
                    if not retry_policy_to_apply:
                        retry_policy_to_apply = DEFAULT_RETRY_POLICY
                    if not retry_policy_to_apply.should_retry(e):
                        if random.random() < self.failed_retry_policy_log_sample_rate:
                            # Sample logging in case logging is too overwhelming.
                            log.info(
                                "Thrift call failed retry policy : %s(%s) :"
                                "%s:%d : time_taken_ms : %s : %s" % (
                                    method_name, handler_args, self.host,
                                    self.port, time_taken_ms, e))
                            # raise exception to stop it from being retried
                        raise t, v, tb
                elif _is_rpc_timeout(e):
                    # rpc socket timeout, not connection socket timeout
                    log.info(
                        "Thrift call failed rpc timeout : %s(%s) :"
                        "%s:%d : time_taken_ms : %s : %s" % (
                            method_name, handler_args, self.host,
                            self.port, time_taken_ms, e))
                    self.statsd_client.increment(
                        "errors.thriftclient.RpcTimeoutError",
                        sample_rate=0.01,
                        tags={'client': self.host})
                    # socket timeout, only reliable way to recover is to tear
                    # down the connection, it is probably good to select a
                    # new host, regardless whether we should retry this request
                    # or not.
                    self.teardown_connection(select_new_host=True)
                    # TODO(Yongsheng): temporarily disable this feature, we need
                    # a way to gauge the server healthiness before we can bring
                    # this feature back.
                    # raise exception to keep it from being retried.
                    # raise self.get_connection_exception_class()(e)
                else:
                    # at this point, we assume it is connectivity issue,
                    # socket read/write errors, or failing to establish
                    # connection, we will need to tear down the connection
                    # and re-establish it for subsequent calls
                    log.info(
                        "Thrift client connection fail : %s(%s) : %s:%d : "
                        "retries_left=%d : time_taken_ms : %s  %r",
                        method_name, handler_args, self.host,
                        self.port, retries_left, time_taken_ms, e)
                    self.statsd_client.increment(
                        "errors.thriftclient.ConnectionError",
                        sample_rate=0.01,
                        tags={'client': self.host})
                    # By default, for the first two retries, try the same host
                    # to rule out intermittent connectivity issue. For the last
                    # retry select a new host randomly.
                    # If ``always_retry_on_new_host`` is set True, always retry
                    # on a new host.
                    if self.always_retry_on_new_host or retries_left == 1:
                        # turn this on when we are ready to penalize bad hosts
                        # self._host_selector.invalidate()
                        self.teardown_connection(select_new_host=True)
                    else:
                        self.teardown_connection(select_new_host=False)

                # Retriable errors, but no retries left, bail.
                if not retries_left:
                    log.info(
                        "Thrift call failed all retries : %s(%s) : "
                        "%s:%d : time_taken_ms: %s %s" % (
                            method_name, handler_args, self.host, self.port,
                            time_taken_ms, e))
                    self.statsd_client.increment(
                        "errors.thriftclient.AllConnectionError",
                        sample_rate=0.01,
                        tags={'client': self.host})
                    # Repack the message and raise as a different exception.
                    raise self.get_connection_exception_class()(e), None, tb

    return method_wrapper

Example 12

Project: pypowervm
Source File: retry.py
View license
def retry(tries=3, delay_func=NO_DELAY,
          retry_except=None, http_codes=DFT_RETRY_CODES, test_func=None,
          resp_checker=NO_CHECKER, limit_except=None, argmod_func=NO_ARGMOD):
    """Retry method decorator.

    :param tries: The max number of calls to the wrapped method.
    :param delay_func: A method to delay before retrying.
        Defaults to no delay.
        The parameters that are sent are:
            - the number of the current try
            - the maximum number of tries
            - the arguments to the decorated method
            - the keyword arguments to the decorated method
        No return value is expected.
    :param retry_except: An exception class (or tuple thereof) to retry if
        received.  Defaults to no exceptions besides the HttpError which is
        handled separately by the http_codes parameter.
    :param http_codes: A list of http response codes to retry if received.
        Default is to not handle any specific http codes.
    :param test_func: A method to call to determine whether to retry. This
        method takes precedence over http codes. That is, if specified, the
        http codes are not considered.
        The parameters that are sent are:
            - the exception that was received
            - the number of the current try
            - the maximum number of tries
            - the arguments to the decorated method
            - the keyword arguments to the decorated method
        The return value is expected to be boolean, True or False, where
            True means to retry the decorated method.
    :param resp_checker: A method to call when no exception is caught, to
        check the response and determine whether to retry.
        The parameters that are sent are:
            - the number of the current try
            - the maximum number of tries
            - the arguments to the decorated method
            - the keyword arguments to the decorated method
        The return value is expected to be boolean, True or False, where
            True means to retry the decorated method.
    :param limit_except: An exception to raise if the number of tries is
        exhausted.
    :param argmod_func: A method to call after delay_func, before retrying, to
                        modify the arguments to the main method.  The input
                        parameters are:
                            - the number of the current try
                            - the maximum number of tries
                            - the non-keyword arguments to the decorated method
                            - the keyword arguments to the decorated method
                        The return is expected to a list and a dict of the
                        new arguments to the decorated method.
                        Example:
                        def argmod(t, m, *a, **k):
                            l = list(a)
                            l[0] += 1
                            k['foo'] = bar
                            return l, k
    :returns: The return value of the wrapped method.
    """
    def _retry(func):
        @functools.wraps(func)
        def __retry(*args, **kwds):
            def _raise_exc():
                if _limit_except:
                    raise _limit_except
                else:
                    raise

            def _test_retry(e):
                # Determine if an exception should be raised
                if (not _test_func(e, try_, _tries, *args, **kwds) or
                        try_ == _tries):
                    _raise_exc()
                # Otherwise, we will continue trying
                return

            def _log_response_retry(try_, max_tries, uri, resp_code):
                LOG.warning(_('Attempt %(retry)d of total %(total)d for URI '
                              '%(uri)s.  Error was a known retry response '
                              'code: %(resp_code)s'),
                            {'retry': try_, 'total': max_tries, 'uri': uri,
                             'resp_code': resp_code})

            def _log_exception_retry(try_, max_tries, exc):
                LOG.warning(_('Attempt %(retry)d of %(total)d failed.  Will '
                              'retry. The exception was:\n %(except)s.'),
                            {'retry': try_, 'total': max_tries, 'except': exc})

            # Standardize input
            # For some reason, if we use the parms in an 'if' directly
            # python throws an exception.  Assigning them avoids it.
            _tries = tries
            _retry_except = retry_except
            _http_codes = http_codes
            _test_func = test_func
            _resp_checker = resp_checker
            _limit_except = limit_except
            _argmod_func = argmod_func

            if _retry_except is None:
                _retry_except = ()
            if _http_codes is None:
                _http_codes = ()
            caller_test_func = _test_func is not None
            if not caller_test_func:
                _test_func = NO_TEST
            if _resp_checker is None:
                _resp_checker = NO_CHECKER
            # Start retries
            for try_ in moves.range(1, _tries+1):
                try:
                    resp = func(*args, **kwds)
                    # No exception raised, call the response checker
                    # If we're on the last iteration, we return the response.
                    # The response checker should raise an exception if
                    # it doesn't want this behavior.
                    if (not _resp_checker(resp, try_, _tries, *args, **kwds)
                            or try_ == _tries):
                        return resp
                except exc.HttpError as e:
                    if caller_test_func or e.response.status in _http_codes:
                        _test_retry(e)
                        _log_response_retry(try_, _tries, e.response.reqpath,
                                            e.response.status)
                    else:
                        _raise_exc()
                except _retry_except as e:
                    _test_retry(e)
                    _log_exception_retry(try_, _tries, e)
                # If we get here then we're going to retry
                delay_func(try_, _tries, *args, **kwds)
                # Adjust arguments if necessary
                args, kwds = _argmod_func(try_, _tries, *args, **kwds)
        return __retry
    return _retry

Example 13

View license
def args_from(original_function,
              only=None,
              allexcept=None,
              inject_kwargs=None,
              inject_docs=None,
              wraps=None,
              update_docstring_args=False):
    """
    Decorator to transfer call signatures - helps to hide ugly *args and **kwargs in delegated calls

    Args:
        original_function (callable): the function to take the call signature from
        only (List[str]): only transfer these arguments (incompatible with `allexcept`)
        wraps (bool): Transfer documentation and attributes from original_function to
            decorated_function, using functools.wraps (default: True if call signature is
            unchanged, False otherwise)
        allexcept (List[str]): transfer all except these arguments (incompatible with `only`)
        inject_kwargs (dict): Inject new kwargs into the call signature
            (of the form ``{argname: defaultvalue}``)
        inject_docs (dict): Add or modifies argument documentation (requires google-style
            docstrings) with a dict of the form `{argname: "(type): description"}`
        update_docstring_args (bool): Update "arguments" section of the docstring using the
           original function's documentation (requires google-style docstrings and wraps=False)

    Note:
        To use arguments from a classes' __init__ method, pass the class itself as
        ``original_function`` - this will also allow us to inject the documentation

    Returns:
        Decorator function
    """
    # NEWFEATURE - verify arguments?

    if only and allexcept:
        raise ValueError('Error in keyword arguments - '
                         'pass *either* "only" or "allexcept", not both')

    origname = get_qualified_name(original_function)

    if hasattr(original_function, '__signature__'):
        sig = original_function.__signature__.replace()
    else:
        sig = funcsigs.signature(original_function)

    # Modify the call signature if necessary
    if only or allexcept or inject_kwargs:
        wraps = if_not_none(wraps, False)
        newparams = []
        if only:
            for param in only:
                newparams.append(sig.parameters[param])
        elif allexcept:
            for name, param in sig.parameters.iteritems():
                if name not in allexcept:
                    newparams.append(param)
        else:
            newparams = sig.parameters.values()
        if inject_kwargs:
            for name, default in inject_kwargs.iteritems():
                newp = funcsigs.Parameter(name, funcsigs.Parameter.POSITIONAL_OR_KEYWORD,
                                          default=default)
                newparams.append(newp)

        newparams.sort(key=lambda param: param._kind)
        sig = sig.replace(parameters=newparams)

    else:
        wraps = if_not_none(wraps, True)

    # Get the docstring arguments
    if update_docstring_args:
        original_docs = GoogleDocArgumentInjector(original_function.__doc__)
        argument_docstrings = collections.OrderedDict((p.name, original_docs.args[p.name])
                                                      for p in newparams)

    def decorator(f):
        """Modify f's call signature (using the `__signature__` attribute)"""
        if wraps:
            fname = original_function.__name__
            f = functools.wraps(original_function)(f)
            f.__name__ = fname  # revert name change
        else:
            fname = f.__name__
        f.__signature__ = sig

        if update_docstring_args or inject_kwargs:
            if not update_docstring_args:
                argument_docstrings = GoogleDocArgumentInjector(f.__doc__).args
            docs = GoogleDocArgumentInjector(f.__doc__)
            docs.args = argument_docstrings

            if not hasattr(f, '__orig_docs'):
                f.__orig_docs = []
            f.__orig_docs.append(f.__doc__)

            f.__doc__ = docs.new_docstring()

        # Only for building sphinx documentation:
        if os.environ.get('SPHINX_IS_BUILDING_DOCS', ""):
            sigstring = '%s%s\n' % (fname, sig)
            if hasattr(f, '__doc__') and f.__doc__ is not None:
                f.__doc__ = sigstring + f.__doc__
            else:
                f.__doc__ = sigstring
        return f

    return decorator

Example 14

Project: djangopackages
Source File: decorators.py
View license
def lru_cache(maxsize=100):
    '''Least-recently-used cache decorator.

    Arguments to the cached function must be hashable.
    Cache performance statistics stored in f.hits and f.misses.
    Clear the cache with f.clear().
    http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used

    '''
    maxqueue = maxsize * 10
    def decorating_function(user_function,
            len=len, iter=iter, tuple=tuple, sorted=sorted, KeyError=KeyError):
        cache = {}                  # mapping of args to results
        queue = collections.deque() # order that keys have been used
        refcount = Counter()        # times each key is in the queue
        sentinel = object()         # marker for looping around the queue
        kwd_mark = object()         # separate positional and keyword args

        # lookup optimizations (ugly but fast)
        queue_append, queue_popleft = queue.append, queue.popleft
        queue_appendleft, queue_pop = queue.appendleft, queue.pop

        @functools.wraps(user_function)
        def wrapper(*args, **kwds):
            # cache key records both positional and keyword args
            key = args
            if kwds:
                key += (kwd_mark,) + tuple(sorted(kwds.items()))

            # record recent use of this key
            queue_append(key)
            refcount[key] += 1

            # get cache entry or compute if not found
            try:
                result = cache[key]
                wrapper.hits += 1
            except KeyError:
                result = user_function(*args, **kwds)
                cache[key] = result
                wrapper.misses += 1

                # purge least recently used cache entry
                if len(cache) > maxsize:
                    key = queue_popleft()
                    refcount[key] -= 1
                    while refcount[key]:
                        key = queue_popleft()
                        refcount[key] -= 1
                    del cache[key], refcount[key]

            # periodically compact the queue by eliminating duplicate keys
            # while preserving order of most recent access
            if len(queue) > maxqueue:
                refcount.clear()
                queue_appendleft(sentinel)
                for key in ifilterfalse(refcount.__contains__,
                                        iter(queue_pop, sentinel)):
                    queue_appendleft(key)
                    refcount[key] = 1


            return result

        def clear():
            cache.clear()
            queue.clear()
            refcount.clear()
            wrapper.hits = wrapper.misses = 0

        wrapper.hits = wrapper.misses = 0
        wrapper.clear = clear
        return wrapper
    return decorating_function

Example 15

Project: xarray
Source File: plot.py
View license
def _plot2d(plotfunc):
    """
    Decorator for common 2d plotting logic

    Also adds the 2d plot method to class _PlotMethods
    """
    commondoc = """
    Parameters
    ----------
    darray : DataArray
        Must be 2 dimensional, unless creating faceted plots
    x : string, optional
        Coordinate for x axis. If None use darray.dims[1]
    y : string, optional
        Coordinate for y axis. If None use darray.dims[0]
    ax : matplotlib axes object, optional
        If None, uses the current axis
    row : string, optional
        If passed, make row faceted plots on this dimension name
    col : string, optional
        If passed, make column faceted plots on this dimension name
    col_wrap : integer, optional
        Use together with ``col`` to wrap faceted plots
    xincrease : None, True, or False, optional
        Should the values on the x axes be increasing from left to right?
        if None, use the default for the matplotlib function
    yincrease : None, True, or False, optional
        Should the values on the y axes be increasing from top to bottom?
        if None, use the default for the matplotlib function
    add_colorbar : Boolean, optional
        Adds colorbar to axis
    add_labels : Boolean, optional
        Use xarray metadata to label axes
    vmin, vmax : floats, optional
        Values to anchor the colormap, otherwise they are inferred from the
        data and other keyword arguments. When a diverging dataset is inferred,
        setting one of these values will fix the other by symmetry around
        ``center``. Setting both values prevents use of a diverging colormap.
        If discrete levels are provided as an explicit list, both of these
        values are ignored.
    cmap : matplotlib colormap name or object, optional
        The mapping from data values to color space. If not provided, this
        will be either be ``viridis`` (if the function infers a sequential
        dataset) or ``RdBu_r`` (if the function infers a diverging dataset).
        When when `Seaborn` is installed, ``cmap`` may also be a `seaborn`
        color palette. If ``cmap`` is seaborn color palette and the plot type
        is not ``contour`` or ``contourf``, ``levels`` must also be specified.
    colors : discrete colors to plot, optional
        A single color or a list of colors. If the plot type is not ``contour``
        or ``contourf``, the ``levels`` argument is required.
    center : float, optional
        The value at which to center the colormap. Passing this value implies
        use of a diverging colormap. Setting it to ``False`` prevents use of a
        diverging colormap.
    robust : bool, optional
        If True and ``vmin`` or ``vmax`` are absent, the colormap range is
        computed with 2nd and 98th percentiles instead of the extreme values.
    extend : {'neither', 'both', 'min', 'max'}, optional
        How to draw arrows extending the colorbar beyond its limits. If not
        provided, extend is inferred from vmin, vmax and the data limits.
    levels : int or list-like object, optional
        Split the colormap (cmap) into discrete color intervals.
    subplot_kws : dict, optional
        Dictionary of keyword arguments for matplotlib subplots. Only applies
        to FacetGrid plotting.
    cbar_ax : matplotlib Axes, optional
        Axes in which to draw the colorbar.
    cbar_kwargs : dict, optional
        Dictionary of keyword arguments to pass to the colorbar.
    **kwargs : optional
        Additional arguments to wrapped matplotlib function

    Returns
    -------
    artist :
        The same type of primitive artist that the wrapped matplotlib
        function returns
    """

    # Build on the original docstring
    plotfunc.__doc__ = '\n'.join((plotfunc.__doc__, commondoc))

    @functools.wraps(plotfunc)
    def newplotfunc(darray, x=None, y=None, ax=None, row=None, col=None,
                    col_wrap=None, xincrease=True, yincrease=True,
                    add_colorbar=None, add_labels=True, vmin=None, vmax=None,
                    cmap=None, center=None, robust=False, extend=None,
                    levels=None, colors=None, subplot_kws=None,
                    cbar_ax=None, cbar_kwargs=None, **kwargs):
        # All 2d plots in xarray share this function signature.
        # Method signature below should be consistent.

        # Decide on a default for the colorbar before facetgrids
        if add_colorbar is None:
            add_colorbar = plotfunc.__name__ != 'contour'

        # Handle facetgrids first
        if row or col:
            allargs = locals().copy()
            allargs.update(allargs.pop('kwargs'))

            # Need the decorated plotting function
            allargs['plotfunc'] = globals()[plotfunc.__name__]

            return _easy_facetgrid(**allargs)

        import matplotlib.pyplot as plt

        # colors is mutually exclusive with cmap
        if cmap and colors:
            raise ValueError("Can't specify both cmap and colors.")
        # colors is only valid when levels is supplied or the plot is of type
        # contour or contourf
        if colors and (('contour' not in plotfunc.__name__) and (not levels)):
            raise ValueError("Can only specify colors with contour or levels")
        # we should not be getting a list of colors in cmap anymore
        # is there a better way to do this test?
        if isinstance(cmap, (list, tuple)):
            warnings.warn("Specifying a list of colors in cmap is deprecated. "
                          "Use colors keyword instead.",
                          DeprecationWarning, stacklevel=3)

        if ax is None:
            ax = plt.gca()

        xlab, ylab = _infer_xy_labels(darray=darray, x=x, y=y)

        # better to pass the ndarrays directly to plotting functions
        xval = darray[xlab].values
        yval = darray[ylab].values
        zval = darray.to_masked_array(copy=False)

        # May need to transpose for correct x, y labels
        # xlab may be the name of a coord, we have to check for dim names
        if darray[xlab].dims[-1] == darray.dims[0]:
            zval = zval.T

        _ensure_plottable(xval, yval)

        if 'contour' in plotfunc.__name__ and levels is None:
            levels = 7  # this is the matplotlib default

        cmap_kwargs = {'plot_data': zval.data,
                       'vmin': vmin,
                       'vmax': vmax,
                       'cmap': colors if colors else cmap,
                       'center': center,
                       'robust': robust,
                       'extend': extend,
                       'levels': levels,
                       'filled': plotfunc.__name__ != 'contour',
                       }

        cmap_params = _determine_cmap_params(**cmap_kwargs)

        if 'contour' in plotfunc.__name__:
            # extend is a keyword argument only for contour and contourf, but
            # passing it to the colorbar is sufficient for imshow and
            # pcolormesh
            kwargs['extend'] = cmap_params['extend']
            kwargs['levels'] = cmap_params['levels']

        # This allows the user to pass in a custom norm coming via kwargs
        kwargs.setdefault('norm', cmap_params['norm'])

        ax, primitive = plotfunc(xval, yval, zval, ax=ax,
                                 cmap=cmap_params['cmap'],
                                 vmin=cmap_params['vmin'],
                                 vmax=cmap_params['vmax'],
                                 **kwargs)

        # Label the plot with metadata
        if add_labels:
            ax.set_xlabel(xlab)
            ax.set_ylabel(ylab)
            ax.set_title(darray._title_for_slice())

        if add_colorbar:
            cbar_kwargs = {} if cbar_kwargs is None else dict(cbar_kwargs)
            cbar_kwargs.setdefault('extend', cmap_params['extend'])
            if cbar_ax is None:
                cbar_kwargs.setdefault('ax', ax)
            else:
                cbar_kwargs.setdefault('cax', cbar_ax)
            cbar = plt.colorbar(primitive, **cbar_kwargs)
            if darray.name and add_labels and 'label' not in cbar_kwargs:
                cbar.set_label(darray.name, rotation=90)
        elif cbar_ax is not None or cbar_kwargs is not None:
            # inform the user about keywords which aren't used
            raise ValueError("cbar_ax and cbar_kwargs can't be used with "
                             "add_colorbar=False.")

        _update_axes_limits(ax, xincrease, yincrease)

        return primitive

    # For use as DataArray.plot.plotmethod
    @functools.wraps(newplotfunc)
    def plotmethod(_PlotMethods_obj, x=None, y=None, ax=None, row=None,
                   col=None, col_wrap=None, xincrease=True, yincrease=True,
                   add_colorbar=None, add_labels=True, vmin=None, vmax=None,
                   cmap=None, colors=None, center=None, robust=False,
                   extend=None, levels=None, subplot_kws=None,
                   cbar_ax=None, cbar_kwargs=None, **kwargs):
        """
        The method should have the same signature as the function.

        This just makes the method work on Plotmethods objects,
        and passes all the other arguments straight through.
        """
        allargs = locals()
        allargs['darray'] = _PlotMethods_obj._da
        allargs.update(kwargs)
        for arg in ['_PlotMethods_obj', 'newplotfunc', 'kwargs']:
            del allargs[arg]
        return newplotfunc(**allargs)

    # Add to class _PlotMethods
    setattr(_PlotMethods, plotmethod.__name__, plotmethod)

    return newplotfunc

Example 16

Project: asyncio
Source File: coroutines.py
View license
def coroutine(func):
    """Decorator to mark coroutines.

    If the coroutine is not yielded from before it is destroyed,
    an error message is logged.
    """
    if _inspect_iscoroutinefunction(func):
        # In Python 3.5 that's all we need to do for coroutines
        # defiend with "async def".
        # Wrapping in CoroWrapper will happen via
        # 'sys.set_coroutine_wrapper' function.
        return func

    if inspect.isgeneratorfunction(func):
        coro = func
    else:
        @functools.wraps(func)
        def coro(*args, **kw):
            res = func(*args, **kw)
            if (futures.isfuture(res) or inspect.isgenerator(res) or
                isinstance(res, CoroWrapper)):
                res = yield from res
            elif _AwaitableABC is not None:
                # If 'func' returns an Awaitable (new in 3.5) we
                # want to run it.
                try:
                    await_meth = res.__await__
                except AttributeError:
                    pass
                else:
                    if isinstance(res, _AwaitableABC):
                        res = yield from await_meth()
            return res

    if not _DEBUG:
        if _types_coroutine is None:
            wrapper = coro
        else:
            wrapper = _types_coroutine(coro)
    else:
        @functools.wraps(func)
        def wrapper(*args, **kwds):
            w = CoroWrapper(coro(*args, **kwds), func=func)
            if w._source_traceback:
                del w._source_traceback[-1]
            # Python < 3.5 does not implement __qualname__
            # on generator objects, so we set it manually.
            # We use getattr as some callables (such as
            # functools.partial may lack __qualname__).
            w.__name__ = getattr(func, '__name__', None)
            w.__qualname__ = getattr(func, '__qualname__', None)
            return w

    wrapper._is_coroutine = True  # For iscoroutinefunction().
    return wrapper

Example 17

Project: python-future
Source File: __init__.py
View license
def disallow_types(argnums, disallowed_types):
    """
    A decorator that raises a TypeError if any of the given numbered
    arguments is of the corresponding given type (e.g. bytes or unicode
    string).

    For example:

        @disallow_types([0, 1], [unicode, bytes])
        def f(a, b):
            pass

    raises a TypeError when f is called if a unicode object is passed as
    `a` or a bytes object is passed as `b`.

    This also skips over keyword arguments, so 

        @disallow_types([0, 1], [unicode, bytes])
        def g(a, b=None):
            pass

    doesn't raise an exception if g is called with only one argument a,
    e.g.:

        g(b'Byte string')

    Example use:

    >>> class newbytes(object):
    ...     @disallow_types([1], [unicode])
    ...     def __add__(self, other):
    ...          pass

    >>> newbytes('1234') + u'1234'      #doctest: +IGNORE_EXCEPTION_DETAIL 
    Traceback (most recent call last):
      ...
    TypeError: can't concat 'bytes' to (unicode) str
    """

    def decorator(function):

        @functools.wraps(function)
        def wrapper(*args, **kwargs):
            # These imports are just for this decorator, and are defined here
            # to prevent circular imports:
            from .newbytes import newbytes
            from .newint import newint
            from .newstr import newstr

            errmsg = "argument can't be {0}"
            for (argnum, mytype) in zip(argnums, disallowed_types):
                # Handle the case where the type is passed as a string like 'newbytes'.
                if isinstance(mytype, str) or isinstance(mytype, bytes):
                    mytype = locals()[mytype]

                # Only restrict kw args only if they are passed:
                if len(args) <= argnum:
                    break

                # Here we use type() rather than isinstance() because
                # __instancecheck__ is being overridden. E.g.
                # isinstance(b'abc', newbytes) is True on Py2.
                if type(args[argnum]) == mytype:
                    raise TypeError(errmsg.format(mytype))

            return function(*args, **kwargs)
        return wrapper
    return decorator

Example 18

Project: qcore
Source File: caching.py
View license
def memoize_with_ttl(ttl_secs=60 * 60 * 24):
    """Memoizes return values of the decorated function for a given time-to-live.

    Similar to l0cache, but the cache persists for the duration of the process, unless clear_cache()
    is called on the function or the time-to-live expires. By default, the time-to-live is set to
    24 hours.

    """

    error_msg = 'Incorrect usage of qcore.caching.memoize_with_ttl: ' \
                'ttl_secs must be a positive integer.'
    assert_is_instance(ttl_secs, six.integer_types, error_msg)
    assert_gt(ttl_secs, 0, error_msg)

    def cache_fun(fun):
        argspec = inspect.getargspec(fun)
        arg_names = argspec.args
        kwargs_defaults = get_kwargs_defaults(argspec)

        def cache_key(args, kwargs):
            return repr(get_args_tuple(args, kwargs, arg_names, kwargs_defaults))

        @functools.wraps(fun)
        def new_fun(*args, **kwargs):
            k = cache_key(args, kwargs)
            current_time = int(time.time())

            # k is not in the cache; perform the function and cache the result.
            if k not in new_fun.__cache or k not in new_fun.__cache_times:
                new_fun.__cache[k] = fun(*args, **kwargs)
                new_fun.__cache_times[k] = current_time
                return new_fun.__cache[k]

            # k is in the cache at this point. Check if the ttl has expired;
            # if so, recompute the value and cache it.
            cache_time = new_fun.__cache_times[k]
            if current_time - cache_time > ttl_secs:
                new_fun.__cache[k] = fun(*args, **kwargs)
                new_fun.__cache_times[k] = current_time

            # finally, return the cached result.
            return new_fun.__cache[k]

        def clear_cache():
            """Removes all cached values for this function."""
            new_fun.__cache.clear()
            new_fun.__cache_times.clear()

        def dirty(*args, **kwargs):
            """Dirties the function for a given set of arguments."""
            k = cache_key(args, kwargs)
            new_fun.__cache.pop(k, None)
            new_fun.__cache_times.pop(k, None)

        new_fun.__cache = {}
        new_fun.__cache_times = {}
        new_fun.clear_cache = clear_cache
        new_fun.dirty = dirty
        return new_fun
    return cache_fun

Example 19

Project: python-semanticversion
Source File: base.py
View license
    @classmethod
    def _comparison_functions(cls, partial=False):
        """Retrieve comparison methods to apply on version components.

        This is a private API.

        Args:
            partial (bool): whether to provide 'partial' or 'strict' matching.

        Returns:
            5-tuple of cmp-like functions.
        """

        def prerelease_cmp(a, b):
            """Compare prerelease components.

            Special rule: a version without prerelease component has higher
            precedence than one with a prerelease component.
            """
            if a and b:
                return identifier_list_cmp(a, b)
            elif a:
                # Versions with prerelease field have lower precedence
                return -1
            elif b:
                return 1
            else:
                return 0

        def build_cmp(a, b):
            """Compare build metadata.

            Special rule: there is no ordering on build metadata.
            """
            if a == b:
                return 0
            else:
                return NotImplemented

        def make_optional(orig_cmp_fun):
            """Convert a cmp-like function to consider 'None == *'."""
            @functools.wraps(orig_cmp_fun)
            def alt_cmp_fun(a, b):
                if a is None or b is None:
                    return 0
                return orig_cmp_fun(a, b)

            return alt_cmp_fun

        if partial:
            return [
                base_cmp,  # Major is still mandatory
                make_optional(base_cmp),
                make_optional(base_cmp),
                make_optional(prerelease_cmp),
                make_optional(build_cmp),
            ]
        else:
            return [
                base_cmp,
                base_cmp,
                base_cmp,
                prerelease_cmp,
                build_cmp,
            ]

Example 20

Project: pyafipws
Source File: utils.py
View license
def inicializar_y_capturar_excepciones(func):
    "Decorador para inicializar y capturar errores (version para webservices)"
    @functools.wraps(func)
    def capturar_errores_wrapper(self, *args, **kwargs):
        try:
            # inicializo (limpio variables)
            self.Errores = []           # listas de str para lenguajes legados
            self.Observaciones = []
            self.errores = []           # listas de dict para usar en python
            self.observaciones = []
            self.Eventos = []
            self.Traceback = self.Excepcion = ""
            self.ErrCode = self.ErrMsg = self.Obs = ""
            # limpio variables especificas del webservice:
            self.inicializar()
            # actualizo los parámetros
            kwargs.update(self.params_in)
            # limpio los parámetros
            self.params_in = {}
            self.params_out = {}
            # llamo a la función (con reintentos)
            retry = self.reintentos + 1
            while retry:
                try:
                    retry -= 1
                    return func(self, *args, **kwargs)
                except socket.error, e:
                    if e[0] not in (10054, 10053):
                        # solo reintentar si el error es de conexión
                        # (10054, 'Connection reset by peer')
                        # (10053, 'Software caused connection abort')
                        raise
                    else:
                        if DEBUG: print e, "Reintentando..."
                        self.log(exception_info().get("msg", ""))

        except SoapFault, e:
            # guardo destalle de la excepción SOAP
            self.ErrCode = unicode(e.faultcode)
            self.ErrMsg = unicode(e.faultstring)
            self.Excepcion = u"%s: %s" % (e.faultcode, e.faultstring, )
            if self.LanzarExcepciones:
                raise
        except Exception, e:
            ex = exception_info()
            self.Traceback = ex.get("tb", "")
            try:
                self.Excepcion = ex.get("msg", "")
            except:
                self.Excepcion = u"<no disponible>"
            if self.LanzarExcepciones:
                raise
            else:
                self.ErrMsg = self.Excepcion
        finally:
            # guardo datos de depuración
            if self.client:
                self.XmlRequest = self.client.xml_request
                self.XmlResponse = self.client.xml_response
    return capturar_errores_wrapper

Example 21

Project: attention-lvcsr
Source File: base.py
View license
def lazy(allocation=None, initialization=None):
    """Makes the initialization lazy.

    This decorator allows the user to define positional arguments which
    will not be needed until the allocation or initialization stage of the
    brick. If these arguments are not passed, it will automatically replace
    them with a custom ``None`` object. It is assumed that the missing
    arguments can be set after initialization by setting attributes with
    the same name.

    Parameters
    ----------
    allocation : list
        A list of argument names that are needed for allocation.
    initialization : list
        A list of argument names that are needed for initialization.

    Examples
    --------
    >>> class SomeBrick(Brick):
    ...     @lazy(allocation=['a'], initialization=['b'])
    ...     def __init__(self, a, b, c='c', d=None):
    ...         print(a, b, c, d)
    >>> brick = SomeBrick('a')
    a NoneInitialization c None
    >>> brick = SomeBrick(d='d', b='b')
    NoneAllocation b c d

    """
    if not allocation:
        allocation = []
    if not initialization:
        initialization = []

    def lazy_wrapper(init):
        def lazy_init(*args, **kwargs):
            self = args[0]
            self.allocation_args = (getattr(self, 'allocation_args',
                                            []) + allocation)
            self.initialization_args = (getattr(self, 'initialization_args',
                                                []) + initialization)
            kwargs = dict_union(args_to_kwargs(args, init), kwargs)
            for allocation_arg in allocation:
                kwargs.setdefault(allocation_arg, NoneAllocation)
            for initialization_arg in initialization:
                kwargs.setdefault(initialization_arg, NoneInitialization)
            return init(**kwargs)
        wraps(init)(lazy_init)
        return lazy_init
    return lazy_wrapper

Example 22

Project: rosbridge_suite
Source File: concurrent.py
View license
def return_future(f):
    """Decorator to make a function that returns via callback return a
    `Future`.

    The wrapped function should take a ``callback`` keyword argument
    and invoke it with one argument when it has finished.  To signal failure,
    the function can simply raise an exception (which will be
    captured by the `.StackContext` and passed along to the ``Future``).

    From the caller's perspective, the callback argument is optional.
    If one is given, it will be invoked when the function is complete
    with `Future.result()` as an argument.  If the function fails, the
    callback will not be run and an exception will be raised into the
    surrounding `.StackContext`.

    If no callback is given, the caller should use the ``Future`` to
    wait for the function to complete (perhaps by yielding it in a
    `.gen.engine` function, or passing it to `.IOLoop.add_future`).

    Usage::

        @return_future
        def future_func(arg1, arg2, callback):
            # Do stuff (possibly asynchronous)
            callback(result)

        @gen.engine
        def caller(callback):
            yield future_func(arg1, arg2)
            callback()

    Note that ``@return_future`` and ``@gen.engine`` can be applied to the
    same function, provided ``@return_future`` appears first.  However,
    consider using ``@gen.coroutine`` instead of this combination.
    """
    replacer = ArgReplacer(f, 'callback')

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        future = TracebackFuture()
        callback, args, kwargs = replacer.replace(
            lambda value=_NO_RESULT: future.set_result(value),
            args, kwargs)

        def handle_error(typ, value, tb):
            future.set_exc_info((typ, value, tb))
            return True
        exc_info = None
        with ExceptionStackContext(handle_error):
            try:
                result = f(*args, **kwargs)
                if result is not None:
                    raise ReturnValueIgnoredError(
                        "@return_future should not be used with functions "
                        "that return values")
            except:
                exc_info = sys.exc_info()
                raise
        if exc_info is not None:
            # If the initial synchronous part of f() raised an exception,
            # go ahead and raise it to the caller directly without waiting
            # for them to inspect the Future.
            raise_exc_info(exc_info)

        # If the caller passed in a callback, schedule it to be called
        # when the future resolves.  It is important that this happens
        # just before we return the future, or else we risk confusing
        # stack contexts with multiple exceptions (one here with the
        # immediate exception, and again when the future resolves and
        # the callback triggers its exception by calling future.result()).
        if callback is not None:
            def run_callback(future):
                result = future.result()
                if result is _NO_RESULT:
                    callback()
                else:
                    callback(future.result())
            future.add_done_callback(wrap(run_callback))
        return future
    return wrapper

Example 23

Project: rosbridge_suite
Source File: testing.py
View license
def gen_test(func=None, timeout=None):
    """Testing equivalent of ``@gen.coroutine``, to be applied to test methods.

    ``@gen.coroutine`` cannot be used on tests because the `.IOLoop` is not
    already running.  ``@gen_test`` should be applied to test methods
    on subclasses of `AsyncTestCase`.

    Example::

        class MyTest(AsyncHTTPTestCase):
            @gen_test
            def test_something(self):
                response = yield gen.Task(self.fetch('/'))

    By default, ``@gen_test`` times out after 5 seconds. The timeout may be
    overridden globally with the ``ASYNC_TEST_TIMEOUT`` environment variable,
    or for each test with the ``timeout`` keyword argument::

        class MyTest(AsyncHTTPTestCase):
            @gen_test(timeout=10)
            def test_something_slow(self):
                response = yield gen.Task(self.fetch('/'))

    .. versionadded:: 3.1
       The ``timeout`` argument and ``ASYNC_TEST_TIMEOUT`` environment
       variable.

    .. versionchanged:: 4.0
       The wrapper now passes along ``*args, **kwargs`` so it can be used
       on functions with arguments.
    """
    if timeout is None:
        timeout = get_async_test_timeout()

    def wrap(f):
        # Stack up several decorators to allow us to access the generator
        # object itself.  In the innermost wrapper, we capture the generator
        # and save it in an attribute of self.  Next, we run the wrapped
        # function through @gen.coroutine.  Finally, the coroutine is
        # wrapped again to make it synchronous with run_sync.
        #
        # This is a good case study arguing for either some sort of
        # extensibility in the gen decorators or cancellation support.
        @functools.wraps(f)
        def pre_coroutine(self, *args, **kwargs):
            result = f(self, *args, **kwargs)
            if isinstance(result, types.GeneratorType):
                self._test_generator = result
            else:
                self._test_generator = None
            return result

        coro = gen.coroutine(pre_coroutine)

        @functools.wraps(coro)
        def post_coroutine(self, *args, **kwargs):
            try:
                return self.io_loop.run_sync(
                    functools.partial(coro, self, *args, **kwargs),
                    timeout=timeout)
            except TimeoutError as e:
                # run_sync raises an error with an unhelpful traceback.
                # If we throw it back into the generator the stack trace
                # will be replaced by the point where the test is stopped.
                self._test_generator.throw(e)
                # In case the test contains an overly broad except clause,
                # we may get back here.  In this case re-raise the original
                # exception, which is better than nothing.
                raise
        return post_coroutine

    if func is not None:
        # Used like:
        #     @gen_test
        #     def f(self):
        #         pass
        return wrap(func)
    else:
        # Used like @gen_test(timeout=10)
        return wrap

Example 24

Project: scrapy-inline-requests
Source File: __init__.py
View license
def inline_requests(method_or_func):
    """A decorator to use coroutine-like spider callbacks.

    Example:

    .. code:: python

        class MySpider(Spider):

            @inline_callbacks
            def parse(self, response):
                next_url = response.urjoin('?next')
                try:
                    next_resp = yield Request(next_url)
                except Exception as e:
                    self.logger.exception("An error occurred.")
                    return
                else:
                    yield {"next_url": next_resp.url}


    You must conform with the following conventions:

    * The decorated method must be a spider method.
    * The decorated method must use the ``yield`` keyword or return a generator.
    * The decorated method must accept ``response`` as the first argument.
    * The decorated method should yield ``Request`` objects without neither
      ``callback`` nor ``errback`` set.

    If your requests don't come back to the generator try setting the flag to
    handle all http statuses:

    .. code:: python

                request.meta['handle_httpstatus_all'] = True

    """
    args = get_args(method_or_func)
    if not args:
        raise TypeError("Function must accept at least one argument.")
    # XXX: hardcoded convention of 'self' as first argument for methods
    if args[0] == 'self':
        def wrapper(self, response, **kwargs):
            callback = create_bound_method(method_or_func, self)

            genwrapper = RequestGenerator(callback, **kwargs)
            return genwrapper(response)
    else:
        warnings.warn("Decorating a non-method function will be deprecated",
                      ScrapyDeprecationWarning, stacklevel=1)

        def wrapper(response, **kwargs):
            genwrapper = RequestGenerator(method_or_func, **kwargs)
            return genwrapper(response)

    return wraps(method_or_func)(wrapper)

Example 25

Project: mock
Source File: trace_decorator.py
View license
def traceLog(log=None):
    def decorator(func):
        @functools.wraps(func)
        def trace(*args, **kw):
            # default to logger that was passed by module, but
            # can override by passing logger=foo as function parameter.
            # make sure this doesn't conflict with one of the parameters
            # you are expecting

            filename = os.path.normcase(inspect.getsourcefile(func))
            func_name = func.__name__
            if hasattr(func, 'func_code'):
                lineno = func.func_code.co_firstlineno
            else:
                lineno = func.__code__.co_firstlineno

            l2 = kw.get('logger', log)
            if l2 is None:
                l2 = logging.getLogger("trace.%s" % func.__module__)
            if isinstance(l2, basestring):
                l2 = logging.getLogger(l2)

            message = "ENTER %s("
            message = message + ', '.join([repr(arg) for arg in args])
            if args and kw:
                message += ', '
            for k, v in list(kw.items()):
                message = message + "%s=%s" % (k, repr(v))
            message = message + ")"

            frame = inspect.getouterframes(inspect.currentframe())[1][0]
            doLog(l2, logging.INFO, os.path.normcase(frame.f_code.co_filename),
                  frame.f_lineno, message, args=[func_name], exc_info=None,
                  func=frame.f_code.co_name)
            try:
                result = "Bad exception raised: Exception was not a derived "\
                         "class of 'Exception'"
                try:
                    result = func(*args, **kw)
                except (KeyboardInterrupt, Exception) as e:
                    result = "EXCEPTION RAISED"
                    doLog(l2, logging.INFO, filename, lineno,
                          "EXCEPTION: %s\n", args=[e],
                          exc_info=sys.exc_info(), func=func_name)
                    raise
            finally:
                doLog(l2, logging.INFO, filename, lineno,
                      "LEAVE %s --> %s\n", args=[func_name, result],
                      exc_info=None, func=func_name)

            return result
        return trace
    return decorator

Example 26

Project: sndlatr
Source File: cache.py
View license
def lru_cache(maxsize=100):
    '''Least-recently-used cache decorator.

    Arguments to the cached function must be hashable.
    Cache performance statistics stored in f.hits and f.misses.
    Clear the cache with f.clear().
    http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used

    '''
    maxqueue = maxsize * 10
    def decorating_function(user_function,
            len=len, iter=iter, tuple=tuple, sorted=sorted, KeyError=KeyError):
        cache = {}                  # mapping of args to results
        queue = collections.deque() # order that keys have been used
        refcount = Counter()        # times each key is in the queue
        sentinel = object()         # marker for looping around the queue
        kwd_mark = object()         # separate positional and keyword args

        # lookup optimizations (ugly but fast)
        queue_append, queue_popleft = queue.append, queue.popleft
        queue_appendleft, queue_pop = queue.appendleft, queue.pop

        @functools.wraps(user_function)
        def wrapper(*args, **kwds):
            # cache key records both positional and keyword args
            key = args
            if kwds:
                key += (kwd_mark,) + tuple(sorted(kwds.items()))

            # record recent use of this key
            queue_append(key)
            refcount[key] += 1

            # get cache entry or compute if not found
            try:
                result = cache[key]
                wrapper.hits += 1
            except KeyError:
                result = user_function(*args, **kwds)
                cache[key] = result
                wrapper.misses += 1

                # purge least recently used cache entry
                if len(cache) > maxsize:
                    key = queue_popleft()
                    refcount[key] -= 1
                    while refcount[key]:
                        key = queue_popleft()
                        refcount[key] -= 1
                    del cache[key], refcount[key]

            # periodically compact the queue by eliminating duplicate keys
            # while preserving order of most recent access
            if len(queue) > maxqueue:
                refcount.clear()
                queue_appendleft(sentinel)
                for key in ifilterfalse(refcount.__contains__,
                                        iter(queue_pop, sentinel)):
                    queue_appendleft(key)
                    refcount[key] = 1


            return result

        def clear():
            cache.clear()
            queue.clear()
            refcount.clear()
            wrapper.hits = wrapper.misses = 0

        wrapper.hits = wrapper.misses = 0
        wrapper.clear = clear
        return wrapper
    return decorating_function

Example 27

Project: flask-caching
Source File: __init__.py
View license
    def cached(self, timeout=None, key_prefix='view/%s', unless=None,
               forced_update=None):
        """Decorator. Use this to cache a function. By default the cache key
        is `view/request.path`. You are able to use this decorator with any
        function by changing the `key_prefix`. If the token `%s` is located
        within the `key_prefix` then it will replace that with `request.path`

        Example::

            # An example view function
            @cache.cached(timeout=50)
            def big_foo():
                return big_bar_calc()

            # An example misc function to cache.
            @cache.cached(key_prefix='MyCachedList')
            def get_list():
                return [random.randrange(0, 1) for i in range(50000)]

            my_list = get_list()

        .. note::

            You MUST have a request context to actually called any functions
            that are cached.

        .. versionadded:: 0.4
            The returned decorated function now has three function attributes
            assigned to it. These attributes are readable/writable.

                **uncached**
                    The original undecorated function

                **cache_timeout**
                    The cache timeout value for this function. For a
                    custom value to take affect, this must be set before the
                    function is called.

                **make_cache_key**
                    A function used in generating the cache_key used.

        :param timeout: Default None. If set to an integer, will cache for that
                        amount of time. Unit of time is in seconds.

        :param key_prefix: Default 'view/%(request.path)s'. Beginning key to .
                           use for the cache key. `request.path` will be the
                           actual request path, or in cases where the
                           `make_cache_key`-function is called from other
                           views it will be the expected URL for the view
                           as generated by Flask's `url_for()`.

                           .. versionadded:: 0.3.4
                               Can optionally be a callable which takes
                               no arguments but returns a string that will
                               be used as the cache_key.

        :param unless: Default None. Cache will *always* execute the caching
                       facilities unless this callable is true.
                       This will bypass the caching entirely.

        :param forced_update: Default None. If this callable is true,
                              cache value will be updated regardless cache
                              is expired or not. Useful for background
                              renewal of cached functions.
        """

        def decorator(f):
            @functools.wraps(f)
            def decorated_function(*args, **kwargs):
                #: Bypass the cache entirely.
                if self._bypass_cache(unless, f, *args, **kwargs):
                    return f(*args, **kwargs)

                try:
                    cache_key = _make_cache_key(args, kwargs, use_request=True)

                    if callable(forced_update) and forced_update() is True:
                        rv = None
                    else:
                        rv = self.cache.get(cache_key)
                except Exception:
                    if current_app.debug:
                        raise
                    logger.exception("Exception possibly due to "
                                     "cache backend.")
                    return f(*args, **kwargs)

                if rv is None:
                    rv = f(*args, **kwargs)
                    try:
                        self.cache.set(
                            cache_key, rv,
                            timeout=decorated_function.cache_timeout
                        )
                    except Exception:
                        if current_app.debug:
                            raise
                        logger.exception("Exception possibly due to "
                                         "cache backend.")
                return rv

            def make_cache_key(*args, **kwargs):
                # Convert non-keyword arguments (which is the way
                # `make_cache_key` expects them) to keyword arguments
                # (the way `url_for` expects them)
                argspec = inspect.getargspec(f)
                for arg_name, arg in zip(argspec.args, args):
                    kwargs[arg_name] = arg

                return _make_cache_key(args, kwargs, use_request=False)

            def _make_cache_key(args, kwargs, use_request):
                if callable(key_prefix):
                    cache_key = key_prefix()
                elif '%s' in key_prefix:
                    if use_request:
                        cache_key = key_prefix % request.path
                    else:
                        cache_key = key_prefix % url_for(f.__name__, **kwargs)
                else:
                    cache_key = key_prefix

                return cache_key

            decorated_function.uncached = f
            decorated_function.cache_timeout = timeout
            decorated_function.make_cache_key = make_cache_key

            return decorated_function
        return decorator

Example 28

Project: flask-caching
Source File: __init__.py
View license
    def memoize(self, timeout=None, make_name=None, unless=None,
                forced_update=None):
        """Use this to cache the result of a function, taking its arguments
        into account in the cache key.

        Information on
        `Memoization <http://en.wikipedia.org/wiki/Memoization>`_.

        Example::

            @cache.memoize(timeout=50)
            def big_foo(a, b):
                return a + b + random.randrange(0, 1000)

        .. code-block:: pycon

            >>> big_foo(5, 2)
            753
            >>> big_foo(5, 3)
            234
            >>> big_foo(5, 2)
            753

        .. versionadded:: 0.4
            The returned decorated function now has three function attributes
            assigned to it.

                **uncached**
                    The original undecorated function. readable only

                **cache_timeout**
                    The cache timeout value for this function.
                    For a custom value to take affect, this must be
                    set before the function is called.

                    readable and writable

                **make_cache_key**
                    A function used in generating the cache_key used.

                    readable and writable


        :param timeout: Default None. If set to an integer, will cache for that
                        amount of time. Unit of time is in seconds.
        :param make_name: Default None. If set this is a function that accepts
                          a single argument, the function name, and returns a
                          new string to be used as the function name.
                          If not set then the function name is used.
        :param unless: Default None. Cache will *always* execute the caching
                       facilities unelss this callable is true.
                       This will bypass the caching entirely.
        :param forced_update: Default None. If this callable is true,
                              cache value will be updated regardless cache
                              is expired or not. Useful for background
                              renewal of cached functions.

        .. versionadded:: 0.5
            params ``make_name``, ``unless``
        """

        def memoize(f):
            @functools.wraps(f)
            def decorated_function(*args, **kwargs):
                #: bypass cache
                if self._bypass_cache(unless, f, *args, **kwargs):
                    return f(*args, **kwargs)

                try:
                    cache_key = decorated_function.make_cache_key(
                        f, *args, **kwargs
                    )
                    if callable(forced_update) and forced_update() is True:
                        rv = None
                    else:
                        rv = self.cache.get(cache_key)
                except Exception:
                    if current_app.debug:
                        raise
                    logger.exception("Exception possibly due to "
                                     "cache backend.")
                    return f(*args, **kwargs)

                if rv is None:
                    rv = f(*args, **kwargs)
                    try:
                        self.cache.set(
                            cache_key, rv,
                            timeout=decorated_function.cache_timeout
                        )
                    except Exception:
                        if current_app.debug:
                            raise
                        logger.exception("Exception possibly due to "
                                         "cache backend.")
                return rv

            decorated_function.uncached = f
            decorated_function.cache_timeout = timeout
            decorated_function.make_cache_key = self._memoize_make_cache_key(
                make_name, decorated_function, forced_update
            )
            decorated_function.delete_memoized = \
                lambda: self.delete_memoized(f)

            return decorated_function
        return memoize

Example 29

Project: unstdlib.py
Source File: functools_.py
View license
def memoized(fn=None, cache=None):
    """ Memoize a function into an optionally-specificed cache container.

    If the `cache` container is not specified, then the instance container is
    accessible from the wrapped function's `memoize_cache` property.

    Example::

        >>> @memoized
        ... def foo(bar):
        ...   print("Not cached.")
        >>> foo(1)
        Not cached.
        >>> foo(1)
        >>> foo(2)
        Not cached.

    Example with a specific cache container (in this case, the
    ``RecentlyUsedContainer``, which will only store the ``maxsize`` most
    recently accessed items)::

        >>> from unstdlib.standard.collections_ import RecentlyUsedContainer
        >>> lru_container = RecentlyUsedContainer(maxsize=2)
        >>> @memoized(cache=lru_container)
        ... def baz(x):
        ...   print("Not cached.")
        >>> baz(1)
        Not cached.
        >>> baz(1)
        >>> baz(2)
        Not cached.
        >>> baz(3)
        Not cached.
        >>> baz(2)
        >>> baz(1)
        Not cached.
        >>> # Notice that the '2' key remains, but the '1' key was evicted from
        >>> # the cache.
    """
    if fn:
        # This is a hack to support both @memoize and @memoize(...)
        return memoized(cache=cache)(fn)

    if cache is None:
        cache = {}

    def decorator(fn):
        wrapped = wraps(fn)(partial(_memoized_call, fn, cache))
        wrapped.memoize_cache = cache
        return wrapped

    return decorator

Example 30

Project: SickGear
Source File: concurrent.py
View license
def return_future(f):
    """Decorator to make a function that returns via callback return a
    `Future`.

    The wrapped function should take a ``callback`` keyword argument
    and invoke it with one argument when it has finished.  To signal failure,
    the function can simply raise an exception (which will be
    captured by the `.StackContext` and passed along to the ``Future``).

    From the caller's perspective, the callback argument is optional.
    If one is given, it will be invoked when the function is complete
    with `Future.result()` as an argument.  If the function fails, the
    callback will not be run and an exception will be raised into the
    surrounding `.StackContext`.

    If no callback is given, the caller should use the ``Future`` to
    wait for the function to complete (perhaps by yielding it in a
    `.gen.engine` function, or passing it to `.IOLoop.add_future`).

    Usage:

    .. testcode::

        @return_future
        def future_func(arg1, arg2, callback):
            # Do stuff (possibly asynchronous)
            callback(result)

        @gen.engine
        def caller(callback):
            yield future_func(arg1, arg2)
            callback()

    ..

    Note that ``@return_future`` and ``@gen.engine`` can be applied to the
    same function, provided ``@return_future`` appears first.  However,
    consider using ``@gen.coroutine`` instead of this combination.
    """
    replacer = ArgReplacer(f, 'callback')

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        future = TracebackFuture()
        callback, args, kwargs = replacer.replace(
            lambda value=_NO_RESULT: future.set_result(value),
            args, kwargs)

        def handle_error(typ, value, tb):
            future.set_exc_info((typ, value, tb))
            return True
        exc_info = None
        with ExceptionStackContext(handle_error):
            try:
                result = f(*args, **kwargs)
                if result is not None:
                    raise ReturnValueIgnoredError(
                        "@return_future should not be used with functions "
                        "that return values")
            except:
                exc_info = sys.exc_info()
                raise
        if exc_info is not None:
            # If the initial synchronous part of f() raised an exception,
            # go ahead and raise it to the caller directly without waiting
            # for them to inspect the Future.
            future.result()

        # If the caller passed in a callback, schedule it to be called
        # when the future resolves.  It is important that this happens
        # just before we return the future, or else we risk confusing
        # stack contexts with multiple exceptions (one here with the
        # immediate exception, and again when the future resolves and
        # the callback triggers its exception by calling future.result()).
        if callback is not None:
            def run_callback(future):
                result = future.result()
                if result is _NO_RESULT:
                    callback()
                else:
                    callback(future.result())
            future.add_done_callback(wrap(run_callback))
        return future
    return wrapper

Example 31

Project: SickGear
Source File: testing.py
View license
def gen_test(func=None, timeout=None):
    """Testing equivalent of ``@gen.coroutine``, to be applied to test methods.

    ``@gen.coroutine`` cannot be used on tests because the `.IOLoop` is not
    already running.  ``@gen_test`` should be applied to test methods
    on subclasses of `AsyncTestCase`.

    Example::

        class MyTest(AsyncHTTPTestCase):
            @gen_test
            def test_something(self):
                response = yield gen.Task(self.fetch('/'))

    By default, ``@gen_test`` times out after 5 seconds. The timeout may be
    overridden globally with the ``ASYNC_TEST_TIMEOUT`` environment variable,
    or for each test with the ``timeout`` keyword argument::

        class MyTest(AsyncHTTPTestCase):
            @gen_test(timeout=10)
            def test_something_slow(self):
                response = yield gen.Task(self.fetch('/'))

    .. versionadded:: 3.1
       The ``timeout`` argument and ``ASYNC_TEST_TIMEOUT`` environment
       variable.

    .. versionchanged:: 4.0
       The wrapper now passes along ``*args, **kwargs`` so it can be used
       on functions with arguments.
    """
    if timeout is None:
        timeout = get_async_test_timeout()

    def wrap(f):
        # Stack up several decorators to allow us to access the generator
        # object itself.  In the innermost wrapper, we capture the generator
        # and save it in an attribute of self.  Next, we run the wrapped
        # function through @gen.coroutine.  Finally, the coroutine is
        # wrapped again to make it synchronous with run_sync.
        #
        # This is a good case study arguing for either some sort of
        # extensibility in the gen decorators or cancellation support.
        @functools.wraps(f)
        def pre_coroutine(self, *args, **kwargs):
            result = f(self, *args, **kwargs)
            if isinstance(result, GeneratorType):
                self._test_generator = result
            else:
                self._test_generator = None
            return result

        coro = gen.coroutine(pre_coroutine)

        @functools.wraps(coro)
        def post_coroutine(self, *args, **kwargs):
            try:
                return self.io_loop.run_sync(
                    functools.partial(coro, self, *args, **kwargs),
                    timeout=timeout)
            except TimeoutError as e:
                # run_sync raises an error with an unhelpful traceback.
                # If we throw it back into the generator the stack trace
                # will be replaced by the point where the test is stopped.
                self._test_generator.throw(e)
                # In case the test contains an overly broad except clause,
                # we may get back here.  In this case re-raise the original
                # exception, which is better than nothing.
                raise
        return post_coroutine

    if func is not None:
        # Used like:
        #     @gen_test
        #     def f(self):
        #         pass
        return wrap(func)
    else:
        # Used like @gen_test(timeout=10)
        return wrap

Example 32

Project: SickRage
Source File: concurrent.py
View license
def return_future(f):
    """Decorator to make a function that returns via callback return a
    `Future`.

    The wrapped function should take a ``callback`` keyword argument
    and invoke it with one argument when it has finished.  To signal failure,
    the function can simply raise an exception (which will be
    captured by the `.StackContext` and passed along to the ``Future``).

    From the caller's perspective, the callback argument is optional.
    If one is given, it will be invoked when the function is complete
    with `Future.result()` as an argument.  If the function fails, the
    callback will not be run and an exception will be raised into the
    surrounding `.StackContext`.

    If no callback is given, the caller should use the ``Future`` to
    wait for the function to complete (perhaps by yielding it in a
    `.gen.engine` function, or passing it to `.IOLoop.add_future`).

    Usage:

    .. testcode::

        @return_future
        def future_func(arg1, arg2, callback):
            # Do stuff (possibly asynchronous)
            callback(result)

        @gen.engine
        def caller(callback):
            yield future_func(arg1, arg2)
            callback()

    ..

    Note that ``@return_future`` and ``@gen.engine`` can be applied to the
    same function, provided ``@return_future`` appears first.  However,
    consider using ``@gen.coroutine`` instead of this combination.
    """
    replacer = ArgReplacer(f, 'callback')

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        future = TracebackFuture()
        callback, args, kwargs = replacer.replace(
            lambda value=_NO_RESULT: future.set_result(value),
            args, kwargs)

        def handle_error(typ, value, tb):
            future.set_exc_info((typ, value, tb))
            return True
        exc_info = None
        with ExceptionStackContext(handle_error):
            try:
                result = f(*args, **kwargs)
                if result is not None:
                    raise ReturnValueIgnoredError(
                        "@return_future should not be used with functions "
                        "that return values")
            except:
                exc_info = sys.exc_info()
                raise
        if exc_info is not None:
            # If the initial synchronous part of f() raised an exception,
            # go ahead and raise it to the caller directly without waiting
            # for them to inspect the Future.
            future.result()

        # If the caller passed in a callback, schedule it to be called
        # when the future resolves.  It is important that this happens
        # just before we return the future, or else we risk confusing
        # stack contexts with multiple exceptions (one here with the
        # immediate exception, and again when the future resolves and
        # the callback triggers its exception by calling future.result()).
        if callback is not None:
            def run_callback(future):
                result = future.result()
                if result is _NO_RESULT:
                    callback()
                else:
                    callback(future.result())
            future.add_done_callback(wrap(run_callback))
        return future
    return wrapper

Example 33

Project: SickRage
Source File: testing.py
View license
def gen_test(func=None, timeout=None):
    """Testing equivalent of ``@gen.coroutine``, to be applied to test methods.

    ``@gen.coroutine`` cannot be used on tests because the `.IOLoop` is not
    already running.  ``@gen_test`` should be applied to test methods
    on subclasses of `AsyncTestCase`.

    Example::

        class MyTest(AsyncHTTPTestCase):
            @gen_test
            def test_something(self):
                response = yield gen.Task(self.fetch('/'))

    By default, ``@gen_test`` times out after 5 seconds. The timeout may be
    overridden globally with the ``ASYNC_TEST_TIMEOUT`` environment variable,
    or for each test with the ``timeout`` keyword argument::

        class MyTest(AsyncHTTPTestCase):
            @gen_test(timeout=10)
            def test_something_slow(self):
                response = yield gen.Task(self.fetch('/'))

    .. versionadded:: 3.1
       The ``timeout`` argument and ``ASYNC_TEST_TIMEOUT`` environment
       variable.

    .. versionchanged:: 4.0
       The wrapper now passes along ``*args, **kwargs`` so it can be used
       on functions with arguments.
    """
    if timeout is None:
        timeout = get_async_test_timeout()

    def wrap(f):
        # Stack up several decorators to allow us to access the generator
        # object itself.  In the innermost wrapper, we capture the generator
        # and save it in an attribute of self.  Next, we run the wrapped
        # function through @gen.coroutine.  Finally, the coroutine is
        # wrapped again to make it synchronous with run_sync.
        #
        # This is a good case study arguing for either some sort of
        # extensibility in the gen decorators or cancellation support.
        @functools.wraps(f)
        def pre_coroutine(self, *args, **kwargs):
            result = f(self, *args, **kwargs)
            if isinstance(result, GeneratorType) or iscoroutine(result):
                self._test_generator = result
            else:
                self._test_generator = None
            return result

        if iscoroutinefunction(f):
            coro = pre_coroutine
        else:
            coro = gen.coroutine(pre_coroutine)

        @functools.wraps(coro)
        def post_coroutine(self, *args, **kwargs):
            try:
                return self.io_loop.run_sync(
                    functools.partial(coro, self, *args, **kwargs),
                    timeout=timeout)
            except TimeoutError as e:
                # run_sync raises an error with an unhelpful traceback.
                # Throw it back into the generator or coroutine so the stack
                # trace is replaced by the point where the test is stopped.
                self._test_generator.throw(e)
                # In case the test contains an overly broad except clause,
                # we may get back here.  In this case re-raise the original
                # exception, which is better than nothing.
                raise
        return post_coroutine

    if func is not None:
        # Used like:
        #     @gen_test
        #     def f(self):
        #         pass
        return wrap(func)
    else:
        # Used like @gen_test(timeout=10)
        return wrap

Example 34

Project: webargs
Source File: core.py
View license
    def use_args(self, argmap, req=None, locations=None, as_kwargs=False, validate=None):
        """Decorator that injects parsed arguments into a view function or method.

        Example usage with Flask: ::

            @app.route('/echo', methods=['get', 'post'])
            @parser.use_args({'name': fields.Str()})
            def greet(args):
                return 'Hello ' + args['name']

        :param argmap: Either a `marshmallow.Schema`, a `dict`
            of argname -> `marshmallow.fields.Field` pairs, or a callable
            which accepts a request and returns a `marshmallow.Schema`.
        :param tuple locations: Where on the request to search for values.
        :param bool as_kwargs: Whether to insert arguments as keyword arguments.
        :param callable validate: Validation function that receives the dictionary
            of parsed arguments. If the function returns ``False``, the parser
            will raise a :exc:`ValidationError`.
        """
        locations = locations or self.locations
        request_obj = req
        # Optimization: If argmap is passed as a dictionary, we only need
        # to generate a Schema once
        if isinstance(argmap, collections.Mapping):
            argmap = argmap2schema(argmap)()

        def decorator(func):
            req_ = request_obj

            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                req_obj = req_

                # if as_kwargs is passed, must include all args
                force_all = as_kwargs

                if not req_obj:
                    req_obj = self.get_request_from_view_args(func, args, kwargs)
                # NOTE: At this point, argmap may be a Schema, or a callable
                parsed_args = self.parse(argmap, req=req_obj,
                                         locations=locations, validate=validate,
                                         force_all=force_all)
                if as_kwargs:
                    kwargs.update(parsed_args)
                    return func(*args, **kwargs)
                else:
                    # Add parsed_args after other positional arguments
                    new_args = args + (parsed_args, )
                    return func(*new_args, **kwargs)
            return wrapper
        return decorator

Example 35

Project: PyFITS
Source File: util.py
View license
def deprecated(since, message='', name='', alternative='', pending=False):
    """
    Used to mark a function as deprecated.

    To mark an attribute as deprecated, replace that attribute with a
    depcrecated property.

    Parameters
    ------------
    since : str
        The release at which this API became deprecated.  This is required.

    message : str, optional
        Override the default deprecation message.  The format specifier
        %(func)s may be used for the name of the function, and %(alternative)s
        may be used in the deprecation message to insert the name of an
        alternative to the deprecated function.

    name : str, optional
        The name of the deprecated function; if not provided the name is
        automatically determined from the passed in function, though this is
        useful in the case of renamed functions, where the new function is just
        assigned to the name of the deprecated function.  For example:
            def new_function():
                ...
            oldFunction = new_function

    alternative : str, optional
        An alternative function that the user may use in place of the
        deprecated function.  The deprecation warning will tell the user about
        this alternative if provided.

    pending : bool, optional
        If True, uses a PyfitsPendingDeprecationWarning instead of a
        PyfitsDeprecationWarning.

    """

    def deprecate(func, message=message, name=name, alternative=alternative,
                  pending=pending):
        if isinstance(func, classmethod):
            try:
                func = func.__func__
            except AttributeError:
                # classmethods in Python2.6 and below lack the __func__
                # attribute so we need to hack around to get it
                method = func.__get__(None, object)
                if hasattr(method, '__func__'):
                    func = method.__func__
                elif hasattr(method, 'im_func'):
                    func = method.im_func
                else:
                    # Nothing we can do really...  just return the original
                    # classmethod
                    return func
            is_classmethod = True
        else:
            is_classmethod = False

        if not name:
            name = func.__name__

        altmessage = ''
        if not message or type(message) == type(deprecate):
            if pending:
                message = ('The %(func)s function will be deprecated in a '
                           'future version.')
            else:
                message = (
                    'The %(func)s function is deprecated as of version '
                    '%(since)s and may be removed in a future version.')
            if alternative:
                altmessage = '\n\n        Use %s instead.' % alternative

        message = ((message % {'func': name, 'alternative': alternative,
                               'since': since}) + altmessage)

        @functools.wraps(func)
        def deprecated_func(*args, **kwargs):
            if pending:
                category = PyfitsPendingDeprecationWarning
            else:
                category = PyfitsDeprecationWarning

            warnings.warn(message, category, stacklevel=2)

            return func(*args, **kwargs)

        old_doc = deprecated_func.__doc__
        if not old_doc:
            old_doc = ''
        old_doc = textwrap.dedent(old_doc).strip('\n')
        altmessage = altmessage.strip()
        if not altmessage:
            altmessage = message.strip()
        new_doc = (('\n.. deprecated:: %(since)s'
                    '\n    %(message)s\n\n' %
                    {'since': since, 'message': altmessage.strip()}) + old_doc)
        if not old_doc:
            # This is to prevent a spurious 'unexected unindent' warning from
            # docutils when the original docstring was blank.
            new_doc += r'\ '

        deprecated_func.__doc__ = new_doc

        if is_classmethod:
            deprecated_func = classmethod(deprecated_func)
        return deprecated_func

    if type(message) == type(deprecate):
        return deprecate(message)

    return deprecate

Example 36

Project: st2
Source File: base.py
View license
def jsexpose(arg_types=None, body_cls=None, status_code=None, content_type='application/json',
             method=None):
    """
    :param arg_types: A list of types for the function arguments (e.g. [str, str, int, bool]).
    :type arg_types: ``list``

    :param body_cls: Request body class. If provided, this class will be used to create an instance
                     out of the request body.
    :type body_cls: :class:`object`

    :param status_code: Response status code.
    :type status_code: ``int``

    :param content_type: Response content type.
    :type content_type: ``str``
    """
    pecan_json_decorate = pecan.expose(
        content_type=content_type,
        generic=False)

    def decorate(f):
        @functools.wraps(f)
        def callfunction(*args, **kwargs):
            args = list(args)
            more = [args.pop(0)]

            def cast_value(value_type, value):
                if value_type == bool:
                    def cast_func(value):
                        return value.lower() in ['1', 'true']
                else:
                    cast_func = value_type

                result = cast_func(value)
                return result

            if body_cls:
                if pecan.request.body:
                    data = pecan.request.json

                    obj = body_cls(**data)
                    try:
                        obj = obj.validate()
                    except (jsonschema.ValidationError, ValueError) as e:
                        raise exc.HTTPBadRequest(detail=e.message,
                                                 comment=traceback.format_exc())
                    except Exception as e:
                        raise exc.HTTPInternalServerError(detail=e.message,
                                                          comment=traceback.format_exc())
                else:
                    obj = None

                more.append(obj)

            if arg_types:
                # Cast and transform arguments based on the provided arg_types specification
                result_args, result_kwargs = get_controller_args_for_types(func=f,
                                                                           arg_types=arg_types,
                                                                           args=args,
                                                                           kwargs=kwargs)
                more = more + result_args
                kwargs.update(result_kwargs)

            args = tuple(more) + tuple(args)

            noop_codes = [http_client.NOT_IMPLEMENTED,
                          http_client.METHOD_NOT_ALLOWED,
                          http_client.FORBIDDEN]

            if status_code and status_code in noop_codes:
                pecan.response.status = status_code
                return json_encode(None)

            try:
                result = f(*args, **kwargs)
            except TypeError as e:
                e = get_exception_for_type_error(func=f, exc=e)
                raise e
            except Exception as e:
                e = get_exception_for_uncaught_api_error(func=f, exc=e)
                raise e

            if status_code:
                pecan.response.status = status_code
            if content_type == 'application/json':
                if is_debugging_enabled():
                    indent = 4
                else:
                    indent = None
                return json_encode(result, indent=indent)
            else:
                return result

        pecan_json_decorate(callfunction)

        return callfunction

    return decorate

Example 37

Project: OWAPI
Source File: v3_util.py
View license
def with_ratelimit(bucket: str, timelimit: int=None, max_reqs: int=0):
    """
    Defines a function to rate limit for.

    Rate limits are stored in `rates.yml`.
    """

    # Compile regular expressions
    def _rl_inner1(func):
        @functools.wraps(func)
        async def _rl_inner2(ctx: HTTPRequestContext, *args, **kwargs):
            """
            Inner ratelimit function.
            """
            if ctx.app.config["owapi_disable_ratelimits"]:
                # Don't bother with ratelimits.
                return await func(ctx, *args, **kwargs)

            # only ratelimit if we have redis. Can't make this decision in
            # outer functions because they are called before globalsettings are set
            if ctx.app.config["owapi_use_redis"]:
                import aioredis
                assert isinstance(ctx.redis, aioredis.Redis)
                # Get the IP.
                ip = ctx.request.ip
                if ip == "127.0.0.1":
                    # We don't want to rate limit localhost.
                    ip = ctx.request.headers.get("X-Real-IP")

                # Build the ratelimit string.
                built = "{bucket}:{ip}:ratelimit".format(bucket=bucket, ip=ip)

                # Check the user agent before.
                user_agent = ctx.request.headers.get("User-Agent")
                if user_agent is None:
                    return BAD_USERAGENT

                if check_default_useragents(user_agent):
                    return BAD_USERAGENT

                # Load the rate limit based on the regular expression provided.
                for regex, rates in compiled:
                    if regex.match(user_agent):
                        break
                else:
                    # UH OH
                    raise RuntimeError("Failed to match User-Agent - did you wipe rates.yml?")

                _timelimit = timelimit or rates.get("time", 1)
                _max_reqs = max_reqs or rates.get("max_reqs", 1)

                # Redis-based ratelimiting.
                # First, check if the key even exists.
                if not (await ctx.redis.exists(built)):
                    # LPUSH, and EXPIRE it.
                    await ctx.redis.lpush(built, _max_reqs)
                    await ctx.redis.expire(built, _timelimit)
                else:
                    # LLEN it.
                    tries = await ctx.redis.llen(built)
                    if tries >= max_reqs:
                        # 429 You Are Being Ratelimited.
                        ttl = await ctx.redis.ttl(built)
                        return {"error": 429, "msg": "you are being ratelimited"}, 429, {"Retry-After": ttl}

                    # LPUSH a `1` or something onto the edge of the list.
                    # The actual value doesn't matter.
                    await ctx.redis.lpush(built, 1)

            # Now, await the underlying function.
            return await func(ctx, *args, **kwargs)

        return _rl_inner2

    return _rl_inner1

Example 38

Project: tornado-zh
Source File: concurrent.py
View license
def return_future(f):
    """Decorator to make a function that returns via callback return a
    `Future`.

    The wrapped function should take a ``callback`` keyword argument
    and invoke it with one argument when it has finished.  To signal failure,
    the function can simply raise an exception (which will be
    captured by the `.StackContext` and passed along to the ``Future``).

    From the caller's perspective, the callback argument is optional.
    If one is given, it will be invoked when the function is complete
    with `Future.result()` as an argument.  If the function fails, the
    callback will not be run and an exception will be raised into the
    surrounding `.StackContext`.

    If no callback is given, the caller should use the ``Future`` to
    wait for the function to complete (perhaps by yielding it in a
    `.gen.engine` function, or passing it to `.IOLoop.add_future`).

    Usage:

    .. testcode::

        @return_future
        def future_func(arg1, arg2, callback):
            # Do stuff (possibly asynchronous)
            callback(result)

        @gen.engine
        def caller(callback):
            yield future_func(arg1, arg2)
            callback()

    ..

    Note that ``@return_future`` and ``@gen.engine`` can be applied to the
    same function, provided ``@return_future`` appears first.  However,
    consider using ``@gen.coroutine`` instead of this combination.
    """
    replacer = ArgReplacer(f, 'callback')

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        future = TracebackFuture()
        callback, args, kwargs = replacer.replace(
            lambda value=_NO_RESULT: future.set_result(value),
            args, kwargs)

        def handle_error(typ, value, tb):
            future.set_exc_info((typ, value, tb))
            return True
        exc_info = None
        with ExceptionStackContext(handle_error):
            try:
                result = f(*args, **kwargs)
                if result is not None:
                    raise ReturnValueIgnoredError(
                        "@return_future should not be used with functions "
                        "that return values")
            except:
                exc_info = sys.exc_info()
                raise
        if exc_info is not None:
            # If the initial synchronous part of f() raised an exception,
            # go ahead and raise it to the caller directly without waiting
            # for them to inspect the Future.
            future.result()

        # If the caller passed in a callback, schedule it to be called
        # when the future resolves.  It is important that this happens
        # just before we return the future, or else we risk confusing
        # stack contexts with multiple exceptions (one here with the
        # immediate exception, and again when the future resolves and
        # the callback triggers its exception by calling future.result()).
        if callback is not None:
            def run_callback(future):
                result = future.result()
                if result is _NO_RESULT:
                    callback()
                else:
                    callback(future.result())
            future.add_done_callback(wrap(run_callback))
        return future
    return wrapper

Example 39

Project: tornado-zh
Source File: testing.py
View license
def gen_test(func=None, timeout=None):
    """Testing equivalent of ``@gen.coroutine``, to be applied to test methods.

    ``@gen.coroutine`` cannot be used on tests because the `.IOLoop` is not
    already running.  ``@gen_test`` should be applied to test methods
    on subclasses of `AsyncTestCase`.

    Example::

        class MyTest(AsyncHTTPTestCase):
            @gen_test
            def test_something(self):
                response = yield gen.Task(self.fetch('/'))

    By default, ``@gen_test`` times out after 5 seconds. The timeout may be
    overridden globally with the ``ASYNC_TEST_TIMEOUT`` environment variable,
    or for each test with the ``timeout`` keyword argument::

        class MyTest(AsyncHTTPTestCase):
            @gen_test(timeout=10)
            def test_something_slow(self):
                response = yield gen.Task(self.fetch('/'))

    .. versionadded:: 3.1
       The ``timeout`` argument and ``ASYNC_TEST_TIMEOUT`` environment
       variable.

    .. versionchanged:: 4.0
       The wrapper now passes along ``*args, **kwargs`` so it can be used
       on functions with arguments.
    """
    if timeout is None:
        timeout = get_async_test_timeout()

    def wrap(f):
        # Stack up several decorators to allow us to access the generator
        # object itself.  In the innermost wrapper, we capture the generator
        # and save it in an attribute of self.  Next, we run the wrapped
        # function through @gen.coroutine.  Finally, the coroutine is
        # wrapped again to make it synchronous with run_sync.
        #
        # This is a good case study arguing for either some sort of
        # extensibility in the gen decorators or cancellation support.
        @functools.wraps(f)
        def pre_coroutine(self, *args, **kwargs):
            result = f(self, *args, **kwargs)
            if isinstance(result, GeneratorType) or iscoroutine(result):
                self._test_generator = result
            else:
                self._test_generator = None
            return result

        if iscoroutinefunction(f):
            coro = pre_coroutine
        else:
            coro = gen.coroutine(pre_coroutine)

        @functools.wraps(coro)
        def post_coroutine(self, *args, **kwargs):
            try:
                return self.io_loop.run_sync(
                    functools.partial(coro, self, *args, **kwargs),
                    timeout=timeout)
            except TimeoutError as e:
                # run_sync raises an error with an unhelpful traceback.
                # Throw it back into the generator or coroutine so the stack
                # trace is replaced by the point where the test is stopped.
                self._test_generator.throw(e)
                # In case the test contains an overly broad except clause,
                # we may get back here.  In this case re-raise the original
                # exception, which is better than nothing.
                raise
        return post_coroutine

    if func is not None:
        # Used like:
        #     @gen_test
        #     def f(self):
        #         pass
        return wrap(func)
    else:
        # Used like @gen_test(timeout=10)
        return wrap

Example 40

Project: ipopo
Source File: utilities.py
View license
def SynchronizedClassMethod(*locks_attr_names, **kwargs):
    """
    A synchronizer decorator for class methods. An AttributeError can be raised
    at runtime if the given lock attribute doesn't exist or if it is None.

    If a parameter ``sorted`` is found in ``kwargs`` and its value is True,
    then the list of locks names will be sorted before locking.

    :param locks_attr_names: A list of the lock(s) attribute(s) name(s) to be
                             used for synchronization
    :return: The decorator method, surrounded with the lock
    """
    # Filter the names (remove empty ones)
    locks_attr_names = [lock_name
                        for lock_name in locks_attr_names
                        if lock_name]

    if not locks_attr_names:
        raise ValueError("The lock names list can't be empty")

    if 'sorted' not in kwargs or kwargs['sorted']:
        # Sort the lock names if requested
        # (locking always in the same order reduces the risk of dead lock)
        locks_attr_names = list(locks_attr_names)
        locks_attr_names.sort()

    def wrapped(method):
        """
        The wrapping method

        :param method: The wrapped method
        :return: The wrapped method
        :raise AttributeError: The given attribute name doesn't exist
        """
        @functools.wraps(method)
        def synchronized(self, *args, **kwargs):
            """
            Calls the wrapped method with a lock
            """
            # Raises an AttributeError if needed
            locks = [getattr(self, attr_name)
                     for attr_name in locks_attr_names]
            locked = collections.deque()
            i = 0

            try:
                # Lock
                for lock in locks:
                    if lock is None:
                        # No lock...
                        raise AttributeError(
                            "Lock '{0}' can't be None in class {1}"
                            .format(locks_attr_names[i], type(self).__name__))

                    # Get the lock
                    i += 1
                    lock.acquire()
                    locked.appendleft(lock)

                # Use the method
                return method(self, *args, **kwargs)

            finally:
                # Unlock what has been locked in all cases
                for lock in locked:
                    lock.release()

                locked.clear()
                del locks[:]

        return synchronized

    # Return the wrapped method
    return wrapped

Example 41

Project: greenhouse
Source File: dns.py
View license
@functools.wraps(socket.getnameinfo)
def getnameinfo(address, flags):
    dns.build_resolver()
    try:
        host, port = address
    except (ValueError, TypeError):
        if not isinstance(address, tuple):
            del address
            raise TypeError('getnameinfo() argument must be a tuple')
        else:
            raise socket.gaierror(
                socket.EAI_NONAME, "Name or service not known")

    if (flags & socket.NI_NAMEREQD) and (flags & socket.NI_NUMERICHOST):
        raise socket.gaierror(
            socket.EAI_NONAME, "Name or service not known")

    if dns.is_ipv4(host):
        try:
            name = dns.reversename.from_address(host)

            results = dns.resolver_obj.query(name, dns.rdatatype.PTR)
            if len(results) > 1:
                raise socket.error(
                    "sockaddr resolved to multiple addresses")

            host = results[0].target.to_text(omit_final_dot=True)
        except dns.exception.Timeout, exc:
            if flags & socket.NI_NAMEREQD:
                raise socket.gaierror(socket.EAI_AGAIN, 'Lookup timed out')
        except dns.resolver.NXDOMAIN:
            return (host, str(port))
        except dns.exception.DNSException, exc:
            if flags & socket.NI_NAMEREQD:
                raise socket.gaierror(
                    socket.EAI_NONAME, "Name or service not known")

    else:
        try:
            ips = dns.resolve(host)

            if len(ips) > 1:
                raise socket.error('sockaddr resolved to multiple addresses')

            if flags & socket.NI_NUMERICHOST:
                host = ips[0].to_text()
        except dns.exception.Timeout, exc:
            if flags & socket.NI_NAMEREQD:
                raise socket.gaierror(socket.EAI_AGAIN, 'Lookup timed out')
        except dns.exception.DNSException, exc:
            if flags & socket.NI_NAMEREQD:
                raise socket.gaierror(
                    socket.EAI_NONAME, "Name or service not known")

    if flags & socket.NI_NUMERICSERV:
        port = str(port)
    else:
        port = socket.getservbyport(
            port, (flags & socket.NI_DGRAM) and 'udp' or 'tcp')

    return host, port

Example 42

Project: flask-cache
Source File: __init__.py
View license
    def cached(self, timeout=None, key_prefix='view/%s', unless=None):
        """
        Decorator. Use this to cache a function. By default the cache key
        is `view/request.path`. You are able to use this decorator with any
        function by changing the `key_prefix`. If the token `%s` is located
        within the `key_prefix` then it will replace that with `request.path`

        Example::

            # An example view function
            @cache.cached(timeout=50)
            def big_foo():
                return big_bar_calc()

            # An example misc function to cache.
            @cache.cached(key_prefix='MyCachedList')
            def get_list():
                return [random.randrange(0, 1) for i in range(50000)]

            my_list = get_list()

        .. note::

            You MUST have a request context to actually called any functions
            that are cached.

        .. versionadded:: 0.4
            The returned decorated function now has three function attributes
            assigned to it. These attributes are readable/writable.

                **uncached**
                    The original undecorated function

                **cache_timeout**
                    The cache timeout value for this function. For a custom value
                    to take affect, this must be set before the function is called.

                **make_cache_key**
                    A function used in generating the cache_key used.

        :param timeout: Default None. If set to an integer, will cache for that
                        amount of time. Unit of time is in seconds.
        :param key_prefix: Default 'view/%(request.path)s'. Beginning key to .
                           use for the cache key.

                           .. versionadded:: 0.3.4
                               Can optionally be a callable which takes no arguments
                               but returns a string that will be used as the cache_key.

        :param unless: Default None. Cache will *always* execute the caching
                       facilities unless this callable is true.
                       This will bypass the caching entirely.
        """

        def decorator(f):
            @functools.wraps(f)
            def decorated_function(*args, **kwargs):
                #: Bypass the cache entirely.
                if callable(unless) and unless() is True:
                    return f(*args, **kwargs)

                try:
                    cache_key = decorated_function.make_cache_key(*args, **kwargs)
                    rv = self.cache.get(cache_key)
                except Exception:
                    if current_app.debug:
                        raise
                    logger.exception("Exception possibly due to cache backend.")
                    return f(*args, **kwargs)

                if rv is None:
                    rv = f(*args, **kwargs)
                    try:
                        self.cache.set(cache_key, rv,
                                   timeout=decorated_function.cache_timeout)
                    except Exception:
                        if current_app.debug:
                            raise
                        logger.exception("Exception possibly due to cache backend.")
                        return f(*args, **kwargs)
                return rv

            def make_cache_key(*args, **kwargs):
                if callable(key_prefix):
                    cache_key = key_prefix()
                elif '%s' in key_prefix:
                    cache_key = key_prefix % request.path
                else:
                    cache_key = key_prefix

                return cache_key

            decorated_function.uncached = f
            decorated_function.cache_timeout = timeout
            decorated_function.make_cache_key = make_cache_key

            return decorated_function
        return decorator

Example 43

Project: flask-cache
Source File: __init__.py
View license
    def memoize(self, timeout=None, make_name=None, unless=None):
        """
        Use this to cache the result of a function, taking its arguments into
        account in the cache key.

        Information on
        `Memoization <http://en.wikipedia.org/wiki/Memoization>`_.

        Example::

            @cache.memoize(timeout=50)
            def big_foo(a, b):
                return a + b + random.randrange(0, 1000)

        .. code-block:: pycon

            >>> big_foo(5, 2)
            753
            >>> big_foo(5, 3)
            234
            >>> big_foo(5, 2)
            753

        .. versionadded:: 0.4
            The returned decorated function now has three function attributes
            assigned to it.

                **uncached**
                    The original undecorated function. readable only

                **cache_timeout**
                    The cache timeout value for this function. For a custom value
                    to take affect, this must be set before the function is called.

                    readable and writable

                **make_cache_key**
                    A function used in generating the cache_key used.

                    readable and writable


        :param timeout: Default None. If set to an integer, will cache for that
                        amount of time. Unit of time is in seconds.
        :param make_name: Default None. If set this is a function that accepts
                          a single argument, the function name, and returns a
                          new string to be used as the function name. If not set
                          then the function name is used.
        :param unless: Default None. Cache will *always* execute the caching
                       facilities unelss this callable is true.
                       This will bypass the caching entirely.

        .. versionadded:: 0.5
            params ``make_name``, ``unless``
        """

        def memoize(f):
            @functools.wraps(f)
            def decorated_function(*args, **kwargs):
                #: bypass cache
                if callable(unless) and unless() is True:
                    return f(*args, **kwargs)

                try:
                    cache_key = decorated_function.make_cache_key(f, *args, **kwargs)
                    rv = self.cache.get(cache_key)
                except Exception:
                    if current_app.debug:
                        raise
                    logger.exception("Exception possibly due to cache backend.")
                    return f(*args, **kwargs)

                if rv is None:
                    rv = f(*args, **kwargs)
                    try:
                        self.cache.set(cache_key, rv,
                                   timeout=decorated_function.cache_timeout)
                    except Exception:
                        if current_app.debug:
                            raise
                        logger.exception("Exception possibly due to cache backend.")
                return rv

            decorated_function.uncached = f
            decorated_function.cache_timeout = timeout
            decorated_function.make_cache_key = self._memoize_make_cache_key(
                                                make_name, decorated_function)
            decorated_function.delete_memoized = lambda: self.delete_memoized(f)

            return decorated_function
        return memoize

Example 44

View license
def deprecated_args(date, instructions, *deprecated_arg_names):
  """Decorator for marking specific function arguments as deprecated.

  This decorator logs a deprecation warning whenever the decorated function is
  called with the deprecated argument. It has the following format:

    Calling <function> (from <module>) with <arg> is deprecated and will be
    removed after <date>. Instructions for updating:
      <instructions>

  <function> will include the class name if it is a method.

  It also edits the docstring of the function: ' (deprecated arguments)' is
  appended to the first line of the docstring and a deprecation notice is
  prepended to the rest of the docstring.

  Args:
    date: String. The date the function is scheduled to be removed. Must be
      ISO 8601 (YYYY-MM-DD).
    instructions: String. Instructions on how to update code using the
      deprecated function.
    *deprecated_arg_names: String. The deprecated arguments.

  Returns:
    Decorated function or method.

  Raises:
    ValueError: If date is not in ISO 8601 format, instructions are empty, or
      the deprecated arguments are not present in the function signature.
  """
  _validate_deprecation_args(date, instructions)
  if not deprecated_arg_names:
    raise ValueError('Specify which argument is deprecated.')

  def deprecated_wrapper(func):
    """Deprecation decorator."""
    decorator_utils.validate_callable(func, 'deprecated_args')

    arg_spec = inspect.getargspec(func)
    deprecated_positions = [
        (i, arg_name) for (i, arg_name) in enumerate(arg_spec.args)
        if arg_name in deprecated_arg_names]
    is_varargs_deprecated = arg_spec.varargs in deprecated_arg_names
    is_kwargs_deprecated = arg_spec.keywords in deprecated_arg_names

    if (len(deprecated_positions) + is_varargs_deprecated + is_kwargs_deprecated
        != len(deprecated_arg_names)):
      known_args = arg_spec.args + [arg_spec.varargs, arg_spec.keywords]
      missing_args = [arg_name for arg_name in deprecated_arg_names
                      if arg_name not in known_args]
      raise ValueError('The following deprecated arguments are not present '
                       'in the function signature: %s. '
                       'Found next arguments: %s.' % (missing_args, known_args))

    @functools.wraps(func)
    def new_func(*args, **kwargs):
      """Deprecation wrapper."""
      invalid_args = []
      for (i, arg_name) in deprecated_positions:
        if i < len(args):
          invalid_args.append(arg_name)
      if is_varargs_deprecated and len(args) > len(arg_spec.args):
        invalid_args.append(arg_spec.varargs)
      if is_kwargs_deprecated and kwargs:
        invalid_args.append(arg_spec.keywords)
      for arg_name in deprecated_arg_names:
        if arg_name in kwargs:
          invalid_args.append(arg_name)
      for arg_name in invalid_args:
        logging.warning(
            'From %s: calling %s (from %s) with %s is deprecated and will '
            'be removed after %s.\nInstructions for updating:\n%s',
            _call_location(), decorator_utils.get_qualified_name(func),
            func.__module__, arg_name, date, instructions)
      return func(*args, **kwargs)
    new_func.__doc__ = _add_deprecated_arg_notice_to_docstring(
        func.__doc__, date, instructions)
    return new_func
  return deprecated_wrapper

Example 45

View license
def deprecated_args(date, instructions, *deprecated_arg_names):
  """Decorator for marking specific function arguments as deprecated.

  This decorator logs a deprecation warning whenever the decorated function is
  called with the deprecated argument. It has the following format:

    Calling <function> (from <module>) with <arg> is deprecated and will be
    removed after <date>. Instructions for updating:
      <instructions>

  <function> will include the class name if it is a method.

  It also edits the docstring of the function: ' (deprecated arguments)' is
  appended to the first line of the docstring and a deprecation notice is
  prepended to the rest of the docstring.

  Args:
    date: String. The date the function is scheduled to be removed. Must be
      ISO 8601 (YYYY-MM-DD).
    instructions: String. Instructions on how to update code using the
      deprecated function.
    *deprecated_arg_names: String. The deprecated arguments.

  Returns:
    Decorated function or method.

  Raises:
    ValueError: If date is not in ISO 8601 format, instructions are empty, or
      the deprecated arguments are not present in the function signature.
  """
  _validate_deprecation_args(date, instructions)
  if not deprecated_arg_names:
    raise ValueError('Specify which argument is deprecated.')

  def deprecated_wrapper(func):
    """Deprecation decorator."""
    decorator_utils.validate_callable(func, 'deprecated_args')

    arg_spec = inspect.getargspec(func)
    deprecated_positions = [
        (i, arg_name) for (i, arg_name) in enumerate(arg_spec.args)
        if arg_name in deprecated_arg_names]
    is_varargs_deprecated = arg_spec.varargs in deprecated_arg_names
    is_kwargs_deprecated = arg_spec.keywords in deprecated_arg_names

    if (len(deprecated_positions) + is_varargs_deprecated + is_kwargs_deprecated
        != len(deprecated_arg_names)):
      known_args = arg_spec.args + [arg_spec.varargs, arg_spec.keywords]
      missing_args = [arg_name for arg_name in deprecated_arg_names
                      if arg_name not in known_args]
      raise ValueError('The following deprecated arguments are not present '
                       'in the function signature: %s. '
                       'Found next arguments: %s.' % (missing_args, known_args))

    @functools.wraps(func)
    def new_func(*args, **kwargs):
      """Deprecation wrapper."""
      invalid_args = []
      for (i, arg_name) in deprecated_positions:
        if i < len(args):
          invalid_args.append(arg_name)
      if is_varargs_deprecated and len(args) > len(arg_spec.args):
        invalid_args.append(arg_spec.varargs)
      if is_kwargs_deprecated and kwargs:
        invalid_args.append(arg_spec.keywords)
      for arg_name in deprecated_arg_names:
        if arg_name in kwargs:
          invalid_args.append(arg_name)
      for arg_name in invalid_args:
        logging.warning(
            'From %s: calling %s (from %s) with %s is deprecated and will '
            'be removed after %s.\nInstructions for updating:\n%s',
            _call_location(), decorator_utils.get_qualified_name(func),
            func.__module__, arg_name, date, instructions)
      return func(*args, **kwargs)
    new_func.__doc__ = _add_deprecated_arg_notice_to_docstring(
        func.__doc__, date, instructions)
    return new_func
  return deprecated_wrapper

Example 46

Project: django-easyextjs4
Source File: __init__.py
View license
    @staticmethod
    def Class(pUrlApis = None, pUrl = None, pId = None, pTimeOut = None, pNameSpace = None, pSession = None):
        
        if pId is not None and not isinstance(pId,str):
            raise ExtJSError('pId must be a string')            
        
        if pNameSpace is not None and not isinstance(pNameSpace,str):
            raise ExtJSError('pNameSpace must be a string')            
        
        if pTimeOut is not None and not isinstance(pTimeOut,int):
            raise ExtJSError('pTimeOut must be an integer')            
        
        if pUrl is not None and not isinstance(pUrl,str):
            raise ExtJSError('pUrl must be a string')            
        
        if pUrlApis is not None and not isinstance(pUrlApis,str):
            raise ExtJSError('pUrlApis must be a string')            
        
        if pSession is not None:
            if isinstance(pSession,bool) and pSession == True:
                pSession = Ext.sessionFromRequest
            elif not inspect.isfunction(pSession):
                raise ExtJSError('pSession must be method or boolean. If it\'s a method it must return a session object. If it\'s boolean with True it will return session from a django request.')

        if pUrlApis is None:
            pUrlApis = 'api.js'
        
        lExt = Ext.__Instance()
        
        lExt.UrlApis = pUrlApis
        lExt.Url = pUrl
        lExt.Id = pId
        lExt.TimeOut = pTimeOut
        lExt.NameSpace = pNameSpace
        
        def decorator(pClass):
    
            if hasattr(pClass,'__ExtJS'):
                raise ExtJSError('Class %s already register for ExtJS' % pClass.__name__)
            
            # Store ExtJS informations on the class            
            pClass.__ExtJS = lExt
            
            # Valid and store Javascript API
            if lExt.UrlApis not in Ext.__URLSAPI:
                Ext.__URLSAPI[lExt.UrlApis] = list()
            else:
                lFirstClass = Ext.__URLSAPI[lExt.UrlApis][0]
                lExtFirst = lFirstClass.__ExtJS
                if lExt.NameSpace is None:
                    # The first class has define a name space it will spread to other classes that have the same UrlApis  
                    lExt.NameSpace = lExtFirst.NameSpace
                else:
                    # For an UrlApis we must define the same name space
                    if lExt.NameSpace != lExtFirst.NameSpace: 
                        raise ExtJSError('Class "%s": A same javascript API ("%s") can not be define with two differents name space.' % (pClass.__name__,lExt.UrlApis))
                
            if lExt.Url is not None:
                lUrl = lExt.Url
            else:
                lUrl = 'Default'
                
                if lExt.NameSpace is not None:
                    lUrl = lExt.NameSpace
                
            lExt.Url = 'Rpc' + lUrl    

            if lExt.Url not in Ext.__URLSRPC:
                 Ext.__URLSRPC[lExt.Url] = dict()
                 
            Ext.__URLSRPC[lExt.Url][pClass.__name__] = pClass
            
            if pClass not in Ext.__URLSAPI[lExt.UrlApis]: 
                Ext.__URLSAPI[lExt.UrlApis].append(pClass)
            
            # Register methods
            lExt.StaticMethods = Ext.__METHODS

            # Register events
            lExt.StaticEvents = dict()

            for lKey in Ext.__EVENTS:
                lEvent = Ext.__EVENTS[lKey]
                if lEvent.ClassName is None:
                    lEvent.ClassName = pClass.__name__
                if lEvent.NameSpace is None:
                    lEvent.NameSpace = lExt.NameSpace
                if lEvent.Url is None:
                    lEvent.Url = 'Evt' + lEvent.NameSpace + lEvent.ClassName + lEvent.Name
                if lEvent.UrlApis is None:
                    lEvent.UrlApis = lExt.UrlApis
                if lEvent.Url in Ext.__URLSEVT:     
                    raise ExtJSError('Url "%s" for event "%s" already exist' % (lEvent.Url, lEvent.Name))
                Ext.__URLSEVT[lEvent.Url] = pClass
                if lEvent.UrlApis not in Ext.__URLSAPI:
                    Ext.__URLSAPI[lEvent.UrlApis] = list()
                if pClass not in Ext.__URLSAPI[lEvent.UrlApis]:
                    Ext.__URLSAPI[lEvent.UrlApis].append(pClass)
                lExt.StaticEvents[lEvent.Url] = lEvent
            
            # Apply a session method if the Session method is not already set by the method
            if pSession is not None:
                for lMethod in lExt.StaticMethods:
                    lMethodInfo = lExt.StaticMethods[lMethod] 
                    if lMethodInfo.Session is None:
                        lParams = list(lMethodInfo.Args)
                        if 'pSession' not in lParams:
                            raise ExtJSError('Method \'%s\' must declare a parameter pSession' % lMethodInfo.Name)
                        else:
                            # Check if pSession is the first parameter
                            if lParams.index('pSession') != 0:
                                raise ExtJSError('Method \'%s\' pSession must be the first parameter' % lMethodInfo.Name)
                            lParams = [lVal for lVal in lParams if lVal != 'pSession']
                            lMethodInfo.Session = pSession
                            lMethodInfo.Args = lParams
                for lEvent in lExt.StaticEvents:
                    lEventInfo = lExt.StaticEvents[lEvent] 
                    if lEventInfo.Session is None:
                        lParams = list(lEventInfo.Args)
                        if 'pSession' not in lParams:
                            raise ExtJSError('Event \'%s\' must declare a parameter pSession' % lEventInfo.Name)
                        else:
                            # Check if pSession is the first parameter
                            if lParams.index('pSession') != 0:
                                raise ExtJSError('Event \'%s\' pSession must be the first parameter' % lEventInfo.Name)
                            lParams = [lVal for lVal in lParams if lVal != 'pSession']
                            lEventInfo.Session = pSession
                            lEventInfo.Args = lParams

            Ext.__METHODS = dict()
            Ext.__EVENTS = dict()   
                
            @functools.wraps(pClass)
            def wrapper(*pArgs, **pKwargs):
                lNewObj = pClass(*pArgs,**pKwargs)
                return lNewObj
                
            return wrapper
    
        return decorator

Example 47

Project: django-easyextjs4
Source File: __init__.py
View license
    @staticmethod
    def StaticEvent(pId = None, pEventName = None, pClassName = None, pNameSpace = None, pParams = None, pInterval = None, pUrl = None, pUrlApis = None, pSession = None):
        
        # Define the provider id that will be define on the javascript side
        if pId is not None and not isinstance(pId,str):
            raise ExtJSError('pId must be a string')            
        
        # Force the event name that will be fire on the javascript side. If it's not specify the event name it's build automatically with the concatanation of
        # the name space, the classe name and the Python function name define as an event
        if pEventName is not None and not isinstance(pEventName,str):
            raise ExtJSError('pEventName must be a string')            

        # You can overwrite the classe but becarefull. The class name will be use to build the name of the event when the answer of the event it sent back.
        # If it's not specify it will take the name of the class
        if pClassName is not None and not isinstance(pClassName,str):
            raise ExtJSError('pClassName must be a string')            
        
        # pNameSpace is define to create a uniq name. Your must be sure it doesn't exist. If it's not specify it will take the name space of the class
        if pNameSpace is not None and not isinstance(pNameSpace,str):
            raise ExtJSError('pNameSpace must be a string')            
        
        # pInterval define how often to poll the server-side in milliseconds. If it's not define by default it's set to every 3 seconds by ExtJS. 
        if pInterval is not None and not isinstance(pInterval,int):
            raise ExtJSError('pInterval must be an integer')            
        
        # Specify the keywork for the URL. This keywork will be associate with the current event. The URL must be uniq for each event. 
        # By default the URL it's build like this: 'Evt' + '<Name space>' + '<Class name>' + 'Event Name' 
        if pUrl is not None and not isinstance(pUrl,str):
            raise ExtJSError('pUrl must be a string')            

        # Specify the javascript file. If it's not define it will take the same as one define for the class.
        if pUrlApis is not None and not isinstance(pUrlApis,str):
            raise ExtJSError('pUrlApis must be a string')            
        
        if pParams is not None and not (type(pParams) == list or type(pParams) == dict or type(pParams) == str or type(pParams) == int or type(pParams) == long or  type(pParams) == float):
            raise ExtJSError('pParams must be a list, dict, string, int, long or float')

        if pSession is not None:
            if isinstance(pSession,bool) and pSession == True:
                pSession = Ext.sessionFromRequest
            elif not inspect.isfunction(pSession):
                raise ExtJSError('pSession must be method or boolean. If it\'s a method it must return a session object. If it\'s boolean with True it will return session from a django request.')
        
        lEventInfo = Ext.__Instance()
        
        lEventInfo.UrlApis = pUrlApis
        lEventInfo.Url = pUrl
        lEventInfo.Id = pId
        lEventInfo.EventName = pEventName
        lEventInfo.ClassName = pClassName
        lEventInfo.NameSpace = pNameSpace
        lEventInfo.Params = pParams
        lEventInfo.Interval = pInterval
        lEventInfo.Session = pSession  
        
        def decorator(pEvent):
    
            if type(pEvent) == staticmethod:
                raise ExtJSError('You must declare @staticmethod before @Ext.StaticEvent')
    
            lArgs = inspect.getargspec(pEvent)
            lParams = list(lArgs.args)
            
            if lEventInfo.Session is not None:
                if 'pSession' not in lArgs.args:
                    raise ExtJSError('You must declare a parameter pSession')
                else:
                    # Remove pSession will be transmit automaticaly by the method Request
                    if lParams != []:
                        # Check if pSession is the first parameter
                        if lParams.index('pSession') != 0:
                            raise ExtJSError('pSession must be the first parameter')
                        lParams = [lVal for lVal in lParams if lVal != 'pSession']
                        
            lEventInfo.Name = pEvent.__name__
            lEventInfo.Args = lParams
            lEventInfo.VarArgs = lArgs.varargs
            lEventInfo.Keywords = lArgs.keywords
            lEventInfo.Defaults = lArgs.defaults
            lEventInfo.Call = pEvent
            
            Ext.__EVENTS[pEvent.__name__] = lEventInfo
        
            @functools.wraps(pEvent)
            def wrapper(*pArgs, **pKwargs):
                lRet = pEvent(*pArgs,**pKwargs)
                return lRet
                
            return wrapper
    
        return decorator

Example 48

Project: topaz
Source File: gateway.py
View license
    def generate_wrapper(self):
        if hasattr(self.func, "__wraps__"):
            wrapped_func = self.func.__wraps__
        else:
            wrapped_func = self.func

        code = wrapped_func.__code__
        if wrapped_func.__defaults__ is not None:
            defaults = wrapped_func.__defaults__
            default_start = code.co_argcount - len(defaults)
        else:
            defaults = []
            default_start = None
        argspec = self.argspec
        self_cls = self.self_cls
        func = self.func

        argnames = code.co_varnames[:code.co_argcount]
        argcount = 0
        for arg in argnames:
            argcount += arg.startswith("w_") or arg in argspec
        min_args = argcount
        for arg, default in zip(reversed(argnames), reversed(defaults)):
            min_args -= arg.startswith("w_") or arg in argspec
        unrolling_argnames = unrolling_iterable(enumerate(argnames))
        takes_args_w = "args_w" in argnames

        @functools.wraps(self.func)
        def wrapper(self, space, args_w, block):
            if (len(args_w) < min_args or
                (not takes_args_w and len(args_w) > argcount)):
                raise space.error(space.w_ArgumentError,
                    "wrong number of arguments (%d for %d)" % (len(args_w), min_args)
                )
            args = ()
            arg_count = 0
            args_w_seen = False
            for i, argname in unrolling_argnames:
                if argname == "self":
                    assert isinstance(self, self_cls)
                    args += (self,)
                elif argname == "args_w":
                    if args_w_seen:
                        raise SystemError("args_w cannot be repeated")
                    args += (args_w[arg_count:],)
                    args_w_seen = True
                elif argname == "block":
                    args += (block,)
                elif argname == "space":
                    args += (space,)
                elif argname.startswith("w_") or argname in argspec:
                    if args_w_seen:
                        raise SystemError("args_w must be the last argument accepted")
                    if len(args_w) > arg_count:
                        if argname.startswith("w_"):
                            args += (args_w[arg_count],)
                        elif argname in argspec:
                            args += (getattr(Coerce, argspec[argname])(space, args_w[arg_count]),)
                    elif default_start is not None and i >= default_start:
                        args += (defaults[i - default_start],)
                    else:
                        raise SystemError("bad arg count")
                    arg_count += 1
                else:
                    raise SystemError("%r not implemented" % argname)
            w_res = func(*args)
            if w_res is None:
                w_res = space.w_nil
            return w_res
        return wrapper

Example 49

Project: tornado
Source File: concurrent.py
View license
def return_future(f):
    """Decorator to make a function that returns via callback return a
    `Future`.

    The wrapped function should take a ``callback`` keyword argument
    and invoke it with one argument when it has finished.  To signal failure,
    the function can simply raise an exception (which will be
    captured by the `.StackContext` and passed along to the ``Future``).

    From the caller's perspective, the callback argument is optional.
    If one is given, it will be invoked when the function is complete
    with `Future.result()` as an argument.  If the function fails, the
    callback will not be run and an exception will be raised into the
    surrounding `.StackContext`.

    If no callback is given, the caller should use the ``Future`` to
    wait for the function to complete (perhaps by yielding it in a
    `.gen.engine` function, or passing it to `.IOLoop.add_future`).

    Usage:

    .. testcode::

        @return_future
        def future_func(arg1, arg2, callback):
            # Do stuff (possibly asynchronous)
            callback(result)

        @gen.engine
        def caller(callback):
            yield future_func(arg1, arg2)
            callback()

    ..

    Note that ``@return_future`` and ``@gen.engine`` can be applied to the
    same function, provided ``@return_future`` appears first.  However,
    consider using ``@gen.coroutine`` instead of this combination.
    """
    replacer = ArgReplacer(f, 'callback')

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        future = TracebackFuture()
        callback, args, kwargs = replacer.replace(
            lambda value=_NO_RESULT: future.set_result(value),
            args, kwargs)

        def handle_error(typ, value, tb):
            future.set_exc_info((typ, value, tb))
            return True
        exc_info = None
        with ExceptionStackContext(handle_error):
            try:
                result = f(*args, **kwargs)
                if result is not None:
                    raise ReturnValueIgnoredError(
                        "@return_future should not be used with functions "
                        "that return values")
            except:
                exc_info = sys.exc_info()
                raise
        if exc_info is not None:
            # If the initial synchronous part of f() raised an exception,
            # go ahead and raise it to the caller directly without waiting
            # for them to inspect the Future.
            future.result()

        # If the caller passed in a callback, schedule it to be called
        # when the future resolves.  It is important that this happens
        # just before we return the future, or else we risk confusing
        # stack contexts with multiple exceptions (one here with the
        # immediate exception, and again when the future resolves and
        # the callback triggers its exception by calling future.result()).
        if callback is not None:
            def run_callback(future):
                result = future.result()
                if result is _NO_RESULT:
                    callback()
                else:
                    callback(future.result())
            future.add_done_callback(wrap(run_callback))
        return future
    return wrapper

Example 50

Project: tornado
Source File: testing.py
View license
def gen_test(func=None, timeout=None):
    """Testing equivalent of ``@gen.coroutine``, to be applied to test methods.

    ``@gen.coroutine`` cannot be used on tests because the `.IOLoop` is not
    already running.  ``@gen_test`` should be applied to test methods
    on subclasses of `AsyncTestCase`.

    Example::

        class MyTest(AsyncHTTPTestCase):
            @gen_test
            def test_something(self):
                response = yield gen.Task(self.fetch('/'))

    By default, ``@gen_test`` times out after 5 seconds. The timeout may be
    overridden globally with the ``ASYNC_TEST_TIMEOUT`` environment variable,
    or for each test with the ``timeout`` keyword argument::

        class MyTest(AsyncHTTPTestCase):
            @gen_test(timeout=10)
            def test_something_slow(self):
                response = yield gen.Task(self.fetch('/'))

    .. versionadded:: 3.1
       The ``timeout`` argument and ``ASYNC_TEST_TIMEOUT`` environment
       variable.

    .. versionchanged:: 4.0
       The wrapper now passes along ``*args, **kwargs`` so it can be used
       on functions with arguments.
    """
    if timeout is None:
        timeout = get_async_test_timeout()

    def wrap(f):
        # Stack up several decorators to allow us to access the generator
        # object itself.  In the innermost wrapper, we capture the generator
        # and save it in an attribute of self.  Next, we run the wrapped
        # function through @gen.coroutine.  Finally, the coroutine is
        # wrapped again to make it synchronous with run_sync.
        #
        # This is a good case study arguing for either some sort of
        # extensibility in the gen decorators or cancellation support.
        @functools.wraps(f)
        def pre_coroutine(self, *args, **kwargs):
            result = f(self, *args, **kwargs)
            if isinstance(result, GeneratorType) or iscoroutine(result):
                self._test_generator = result
            else:
                self._test_generator = None
            return result

        if iscoroutinefunction(f):
            coro = pre_coroutine
        else:
            coro = gen.coroutine(pre_coroutine)

        @functools.wraps(coro)
        def post_coroutine(self, *args, **kwargs):
            try:
                return self.io_loop.run_sync(
                    functools.partial(coro, self, *args, **kwargs),
                    timeout=timeout)
            except TimeoutError as e:
                # run_sync raises an error with an unhelpful traceback.
                # Throw it back into the generator or coroutine so the stack
                # trace is replaced by the point where the test is stopped.
                self._test_generator.throw(e)
                # In case the test contains an overly broad except clause,
                # we may get back here.  In this case re-raise the original
                # exception, which is better than nothing.
                raise
        return post_coroutine

    if func is not None:
        # Used like:
        #     @gen_test
        #     def f(self):
        #         pass
        return wrap(func)
    else:
        # Used like @gen_test(timeout=10)
        return wrap