Skip to content

Commit

Permalink
Merge 3b4708b into 1fd3913
Browse files Browse the repository at this point in the history
  • Loading branch information
xethorn committed Jun 3, 2015
2 parents 1fd3913 + 3b4708b commit 5079be7
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 3 deletions.
123 changes: 123 additions & 0 deletions garcon/param.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
"""
Param
=====
Params are values that are passed to the activities. They are either provided
by the execution context (see Param) or are statically provided at the runtime
of the activity (see StaticParam). Custom params should extend the Param class.
Note:
Make sure the custom param class lists out all the dependencies to the
execution context in `requirements`.
"""


class BaseParam:
"""Base Param Class.
Provides the structure and required methods of any param class.
"""

@property
def requirements(self):
"""Return the requirements for this param.
"""

return
yield

def get_data(self, context):
"""Get the data.
Args:
context (dict): the context (optional) in which the data might be
found. For Static Param this won't be necessary.
"""

raise NotImplementedError()


class Param(BaseParam):

def __init__(self, context_key):
"""Create a default param.
Args:
context_key (str): the context key.
"""

self.context_key = context_key

@property
def requirements(self):
"""Return the requirements for this param.
"""

yield self.context_key

def get_data(self, context):
"""Get value from the context.
Args:
context (dict): the context in which the data might be found based
on the key provided.
Return:
obj: an object from the context that corresponds to the context
key.
"""

return context.get(self.context_key, None)


class StaticParam(BaseParam):

def __init__(self, value):
"""Create a static param.
Args:
value (str): the value of the param.
"""

self.value = value

def get_data(self, context):
"""Get value from the context.
Args:
context (dict): execution context (not used.)
"""


return self.value


def get_all_requirements(params):
"""Get all the requirements from a list of params.
Args:
params (list): The list of params.
"""

requirements = []
for param in params:
requirements += list(param.requirements)
return requirements


def parametrize(requirement):
"""Parametrize a requirement.
Args:
requirement (*): the requirement to parametrize.
"""

if isinstance(requirement, str):
return Param(requirement)
elif isinstance(requirement, BaseParam):
return requirement
raise UnknownParamException()


class UnknownParamException(Exception):
pass
17 changes: 15 additions & 2 deletions garcon/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import copy

from garcon import param


def decorate(timeout=None, heartbeat=None, enable_contextify=True):
"""Generic task decorator for tasks.
Expand Down Expand Up @@ -167,6 +169,10 @@ def increase_dynamodb_throughtput(

def fill(namespace=None, **requirements):

requirements = {
key: param.parametrize(current_param)
for key, current_param in requirements.items()}

def wrapper(context, **kwargs):
kwargs.update(
fill_function_call(
Expand All @@ -181,7 +187,10 @@ def wrapper(context, **kwargs):
# Keep a record of the requirements value. This allows us to trim the
# size of the context sent to the activity as an input.
_link_decorator(fn, wrapper)
_decorate(wrapper, 'requirements', requirements.values())
_decorate(
wrapper,
'requirements',
param.get_all_requirements(requirements.values()))
return wrapper

fn.fill = fill
Expand Down Expand Up @@ -228,7 +237,8 @@ def fill_function_call(fn, requirements, activity, context):
kwargs = dict()

for argument in function_arguments:
value = context.get(requirements.get(argument))
param = requirements.get(argument, None)
value = None

if argument == 'context':
raise Exception(
Expand All @@ -238,6 +248,9 @@ def fill_function_call(fn, requirements, activity, context):
elif argument == 'activity':
value = activity

elif param:
value = param.get_data(context)

kwargs.update({
argument: value
})
Expand Down
77 changes: 77 additions & 0 deletions tests/test_param.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import pytest

from garcon import param


def test_base_param_class():
"""Test the base class: cannot get data and return no requirements.
"""

current_param = param.BaseParam()
with pytest.raises(NotImplementedError):
current_param.get_data({})

assert not list(current_param.requirements)


def test_static_param():
"""Test the behavior of the static param class
"""

message = 'Hello World'
current_param = param.StaticParam(message)
assert current_param.get_data({}) is message
assert not list(current_param.requirements)


def test_default_param():
"""Test the behavior of the default param class.
"""

key = 'context.key'
message = 'Hello World'
current_param = param.Param(key)
requirements = list(current_param.requirements)
assert current_param.get_data({key: message}) is message
assert requirements[0] is key


def test_all_requirements():
"""Test getting all the requirements.
"""

keys = ['context.key1', 'context.key2', 'context.key3']
manual_keys = ['context.manual_key1', 'context.manual_key2']
params = [param.Param(key) for key in keys]
params += manual_keys
params += [param.StaticParam('Value')]
params = [param.parametrize(current_param) for current_param in params]

resp = param.get_all_requirements(params)
for key in keys:
assert key in resp

for manual_key in manual_keys:
assert manual_key in resp

assert 'Value' not in resp


def test_parametrize():
"""Test parametrize.
Parametrize only allows objects that inherits BaseParam or string.
"""

keys = ['context.key1', 'context.key2', 'context.key3']
manual_keys = ['context.manual_key1', 'context.manual_key2']
params = [param.Param(key) for key in keys]
params += manual_keys
params += [param.StaticParam('Value')]
params = [param.parametrize(current_param) for current_param in params]

for current_param in params:
assert isinstance(current_param, param.BaseParam)

with pytest.raises(param.UnknownParamException):
param.parametrize(list('Unknown'))
5 changes: 4 additions & 1 deletion tests/test_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest

from garcon import task
from garcon import param


def test_timeout_decorator():
Expand Down Expand Up @@ -301,7 +302,9 @@ def test_fill_function_call():
def test_function(activity, arg_one, key, kwarg_one=None, kwarg_two=None):
pass

requirements = dict(arg_one='context.arg', kwarg_one='context.kwarg')
requirements = dict(
arg_one=param.Param('context.arg'),
kwarg_one=param.Param('context.kwarg'))
activity = None
context = {
'context.arg': 'arg.value',
Expand Down

0 comments on commit 5079be7

Please sign in to comment.