Skip to content
This repository has been archived by the owner on Apr 16, 2022. It is now read-only.

Commit

Permalink
after-hook decorator functions, clean up lock in @Singular
Browse files Browse the repository at this point in the history
  • Loading branch information
haliphax committed Nov 1, 2016
1 parent ab88094 commit 3d5d213
Showing 1 changed file with 33 additions and 9 deletions.
42 changes: 33 additions & 9 deletions rodario/decorators.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
""" Function decorators for rodario framework """


# pylint: disable=R0903
# pylint: disable=R0903,W0613,W0212
class DecoratedMethod(object):

""" Generic decorated method """

def __init__(self, func, decorations=None, bindings=None):
def __init__(self, func, decorations=None, before=None, after=None):
"""
Wrap the given function.
:param instancemethod func: The function to wrap
:param set decorations: The decorator tags to attach
:param list before: The list of before-hook functions
:param list after: The list of after-hook functions
"""

self._func = func
self._instance = None
self.decorations = set(decorations) if decorations is not None else set()
self.bindings = list(bindings) if bindings is not None else list()
self.before = list(before) if before is not None else list()
self.after = list(after) if after is not None else list()

def __get__(self, obj, cls=None):
"""
Expand All @@ -40,14 +44,23 @@ def __call__(self, *args, **kwargs):

result = None

# call each of its bindings first
for callee in self.bindings:
# call each of its before-hook bindings first
for callee in self.before:
result = callee(self._instance, *args, **kwargs)

if result is not None:
return result

result = self._func(self._instance, *args, **kwargs)
mutated = None

# now call each of the after-hook bindings
for callee in self.after:
mutated = callee(self._instance, result, *args, **kwargs)

if mutated is not None:
return mutated

return result

def blocking(func):
Expand Down Expand Up @@ -83,8 +96,7 @@ def singular(func):
expiry = 2
context = None

# pylint: disable=W0613,W0212
def call_singular(self, *args, **kwargs):
def before_singular(self, *args, **kwargs):
"""
Call the method if we can get a lock.
Expand All @@ -110,11 +122,23 @@ def call_singular(self, *args, **kwargs):
# we have the lock; give it a TTL and pass through
self._redis.expire(lock_name, expiry)

def after_singular(self, result, *args, **kwargs):
"""
Clean up the lock.
"""

lock_context = 'global.lock' if not context else context
lock_name = '%s:%s' % (lock_context, func.__name__)
self._redis.delete(lock_name)

# if it's already a DecoratedMethod, just add to it
if isinstance(func, DecoratedMethod):
func.decorations.add('singular')
func.bindings.append(call_singular)
func.before.append(before_singular)
func.after.append(after_singular)

return func

# otherwise, instantiate a new one with our wrapper/bindings by default
return DecoratedMethod(func, ('singular',), (call_singular,))
return DecoratedMethod(func, ('singular',), (before_singular,),
(after_singular,))

0 comments on commit 3d5d213

Please sign in to comment.