enable all combinator tests.
diff --git a/src/composer/__init__.py b/src/composer/__init__.py
index a80dc4b..f405f02 100644
--- a/src/composer/__init__.py
+++ b/src/composer/__init__.py
@@ -38,7 +38,7 @@
     return _composer.loop_nosave(test, body)
 
 def do(body, handler):
-    return _composer._compose('do', (body, handler))
+    return _composer._compose('try', (body, handler))
 
 def doloop(body, test):
     return _composer.doloop(body, test)
diff --git a/src/composer/composer.py b/src/composer/composer.py
index c7effd7..260de52 100644
--- a/src/composer/composer.py
+++ b/src/composer/composer.py
@@ -193,6 +193,7 @@
             except OSError:
                 raise ComposerError('Invalid argument', fun)
 
+        print(fun)
         if isinstance(fun, str):
             # standardize function name
             fun = re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(', 'def func(', fun)
@@ -540,6 +541,8 @@
                 code += 'def main(args):'
                 code += '\n    return conductor()(args)'
 
+                print(code)
+
                 composition.action = { 'exec': { 'kind': 'python:3', 'code':code }, 'annotations': [{ 'key': 'conductor', 'value': str(composition.composition) }, { 'key': 'composer', 'value': __version__ }] }
 
                 del composition.composition
diff --git a/src/composer/conductor.py b/src/composer/conductor.py
index 83f213c..87ec25d 100644
--- a/src/composer/conductor.py
+++ b/src/composer/conductor.py
@@ -109,8 +109,8 @@
     def guarded_invoke(params):
         try:
             return invoke(params)
-        except Exception as error:
-            return internalError(error)
+        except Exception as err:
+            return internalError(err)
 
     def invoke(params):
         ''' do invocation '''
@@ -130,8 +130,11 @@
                 while len(stack) > 0:
                     first = stack[0]
                     stack = stack[1:]
-                    if 'catch' in first and isinstance(first['catch'], int):
-                        break
+                    if 'catch' in first:
+                        state = first['catch']
+                        if isinstance(state, int):
+                            break
+
 
         # restore state and stack when resuming
         if '$resume' in params:
@@ -152,7 +155,7 @@
             view = []
             n = 0
             for frame in stack:
-                if frame['let'] is None:
+                if 'let' in frame and frame['let'] is None:
                     n += 1
                 elif 'let' in frame:
                     if n == 0:
@@ -164,7 +167,6 @@
             # update value of topmost matching symbol on stack if any
             def set(symbol, value):
                 lets = [element for element in view if 'let' in element and symbol in element['let']]
-                print(lets)
                 if len(lets) > 0:
                     element = lets[0]
                     element['let'][symbol] = value # TODO: JSON.parse(JSON.stringify(value))
@@ -230,8 +232,8 @@
 
                 if callable(result):
                     result = { 'error': 'State '+str(current)+' evaluated to a function' }
-                # if a function has only side effects and no return value (or return None), return params
 
+                # if a function has only side effects and no return value (or return None), return params
                 params = params if result is None else result
                 inspect_errors()
             elif jsonv['type'] == 'empty':
diff --git a/src/openwhisk/openwhisk.py b/src/openwhisk/openwhisk.py
index 88ff7e1..dbe196e 100644
--- a/src/openwhisk/openwhisk.py
+++ b/src/openwhisk/openwhisk.py
@@ -65,8 +65,7 @@
             # we turn >=400 statusCode responses into exceptions
             error = Exception()
             error.status_code = resp.status_code
-            error.error = resp.reason
-            print(resp.reason)
+            error.error = resp.json()
             raise error
         else:
             # otherwise, the response body is the expected return value
diff --git a/tests/test_composer.py b/tests/test_composer.py
index 9fa9059..95948dd 100644
--- a/tests/test_composer.py
+++ b/tests/test_composer.py
@@ -28,6 +28,51 @@
     define({ 'name': 'isNotOne', 'action': 'function main({n}) { return { value: n != 1 } }', 'kind': 'nodejs:default' })
     define({ 'name': 'isEven', 'action': 'function main({n}) { return { value: n % 2 == 0 } }', 'kind': 'nodejs:default'})
 
+def isEven(env, args):
+    return args['n'] % 2 == 0
+
+def set_then_true(env, args):
+    args['then'] = True
+
+def set_else_true(env, args):
+    args['else'] = True
+
+def dec_n(env, args):
+    return {'n': args['n'] - 1 }
+
+def cond_false(env, args):
+    return False
+
+def cond_nosave(env, args):
+    return { 'n': args['n'], 'value': args['n'] != 1 }
+
+def cond_true(env, args):
+    return True
+
+def return_error_message(env, args):
+    return {'message': args['error']}
+
+def set_error(env, args):
+    return { 'error': 'foo' }
+
+def set_p_4(env, args):
+    return { 'p': 4 }
+
+def nest_params(env, args):
+    return { 'params': args }
+
+def get_x(env, args):
+    return env['x']
+
+def get_x_plus_y(env, args):
+    return env['x'] + env['y']
+
+def get_value_plus_x(env, args):
+    return args['value'] + env['x']
+
+def noop(env, args):
+    pass
+
 class TestAction:
     def test_action_true(self):
         ''' action must return true '''
@@ -93,9 +138,6 @@
         except composer.ComposerError as error:
             assert error.message == 'Invalid argument'
 
-def isEven(env, args):
-    return args['n'] % 2 == 0
-
 class TestFunction:
 
     def test_function_true(self):
@@ -142,12 +184,6 @@
         activation = invoke(composer.seq('TripleAndIncrement', 'DivideByTwo', 'DivideByTwo'), { 'n': 5 })
         assert activation['response']['result'] == { 'n': 4 }
 
-def set_then_true(env, args):
-    args['then'] = True
-
-def set_else_true(env, args):
-    args['else'] = True
-
 class TestIf:
     def test_condition_true(self):
         activation = invoke(composer.when('isEven', 'DivideByTwo', 'TripleAndIncrement'), { 'n': 4 })
@@ -173,15 +209,6 @@
         activation = invoke(composer.when_nosave('isEven', set_then_true, set_else_true), { 'n': 3 })
         assert activation['response']['result'] == { 'value': False, 'else': True }
 
-def dec_n(env, args):
-    return {'n': args['n'] - 1 }
-
-def cond_false(env, args):
-    return False
-
-def cond_nosave(env, args):
-    return { 'n': args['n'], 'value': args['n'] != 1 }
-
 class TestLoop:
 
     def test_a_few_iterations(self) :
@@ -196,117 +223,112 @@
         activation = invoke(composer.loop_nosave(cond_nosave, dec_n), { 'n': 4 })
         assert activation['response']['result'] == { 'value': False, 'n': 1 }
 
-@pytest.mark.skip(reason='need python conductor')
 class TestDoLoop:
 
     def test_a_few_iterations(self) :
-        activation = invoke(composer.doloop('({ n }) => ({ n: n - 1 })', 'isNotOne'), { 'n': 4 })
+        activation = invoke(composer.doloop(dec_n, 'isNotOne'), { 'n': 4 })
         assert activation['response']['result'] == { 'n': 1 }
 
     def test_one_iteration(self) :
-        activation = invoke(composer.doloop('({ n }) => ({ n: n - 1 })', '() => false'), { 'n': 1 })
+        activation = invoke(composer.doloop(dec_n, cond_false), { 'n': 1 })
         assert activation['response']['result'] == { 'n': 0 }
 
     def test_nosave_option(self) :
-        activation = invoke(composer.doloop_nosave(('{ n }) => ({ n: n - 1 })', '({ n }) => ({ n, value: n !== 1 }))'), { 'n': 4 }))
+        activation = invoke(composer.doloop_nosave(dec_n, cond_nosave), { 'n': 4 })
         assert activation['response']['result'] == { 'value': False, 'n': 1 }
 
-@pytest.mark.skip(reason='need python conductor')
 class TestDo: # Try
     def test_no_error(self):
-        activation = invoke(composer.do('() => true', 'error => ({ message: error.error })'), None)
+        activation = invoke(composer.do(cond_true, return_error_message), {})
         assert activation['response']['result'] == { 'value': True }
 
     def test_error(self) :
-        activation = invoke(composer.do('() => ({ error: "foo" })', 'error => ({ message: error.error })'))
+        activation = invoke(composer.do(set_error, return_error_message), {})
         assert activation['response']['result'] == { 'message': 'foo' }
 
     def test_try_must_throw(self) :
-        activation = invoke(composer.do(composer.task(None), 'error => ({ message: error.error }))', { 'error': 'foo' }))
+        activation = invoke(composer.do(composer.task(None), return_error_message), { 'error': 'foo' })
         assert activation['response']['result'] == { 'message': 'foo' }
 
     def test_while_must_throw(self) :
-        activation = invoke(composer.do(composer.loop(composer.literal(False), None), 'error => ({ message: error.error })'), { 'error': 'foo' })
+        activation = invoke(composer.do(composer.loop(composer.literal(False), None), return_error_message), { 'error': 'foo' })
         assert activation['response']['result'] == { 'message': 'foo' }
 
     def test_if_must_throw(self) :
-        activation = invoke(composer.do(composer.when(composer.literal(False), None), 'error => ({ message: error.error })'), { 'error': 'foo' })
+        activation = invoke(composer.do(composer.when(composer.literal(False), None), return_error_message), { 'error': 'foo' })
         assert activation['response']['result'] == { 'message': 'foo' }
 
     def test_retain(self) :
-        activation = invoke(composer.retain(composer.do('() => ({ p: 4 })', None)), { 'n': 3 })
+        activation = invoke(composer.retain(composer.do(set_p_4, None)), { 'n': 3 })
         assert activation['response']['result'] == { 'params': { 'n': 3 }, 'result': { 'p': 4 } }
 
-@pytest.mark.skip(reason='need python conductor')
 class TestEnsure: # Finally
 
     def test_no_error(self) :
-        activation = invoke(composer.ensure('() => true', 'params => ({ params })'))
+        activation = invoke(composer.ensure(cond_true, nest_params), {})
         assert activation['response']['result'] == { 'params': { 'value': True } }
 
     def test_error(self) :
-        activation = invoke(composer.ensure('() => ({ error: "foo" })', 'params => ({ params })'))
+        activation = invoke(composer.ensure(set_error, nest_params), {})
         assert activation['response']['result'] == { 'params': { 'error': 'foo' } }
 
-@pytest.mark.skip(reason='need python conductor')
 class TestLet:
 
     def test_one_variable(self) :
-        activation = invoke(composer.let({ 'x': 42 }, '() => x'))
+        activation = invoke(composer.let({ 'x': 42 }, get_x), {})
         assert activation['response']['result'] == { 'value': 42 }
 
     def test_masking(self) :
-        activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 }, '() => x')))
-        assert activation['response']['result'] == { value: 69 }
+        activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 }, get_x)), {})
+        assert activation['response']['result'] == { 'value': 69 }
 
     def test_two_variables(self) :
-        activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'y': 69 }, '() => x + y')))
+        activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'y': 69 }, get_x_plus_y)), {})
         assert activation['response']['result'] == { 'value': 111 }
 
     def test_two_variables_combined(self) :
-        activation = invoke(composer.let({ 'x': 42, 'y': 69 }, '() => x + y'))
+        activation = invoke(composer.let({ 'x': 42, 'y': 69 }, get_x_plus_y), {})
         assert activation['response']['result'] == { 'value': 111 }
 
     def test_scoping(self) :
-        activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 }, '() => x'), '({ value }) => value + x'))
+        activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 }, get_x), get_value_plus_x), {})
         assert activation['response']['result'] == { 'value': 111 }
 
     def test_invalid_argument(self):
         try:
             invoke(composer.let(invoke))
             assert False
-        except Exception as error:
+        except composer.ComposerError as error:
             assert error.message.startswith('Invalid argument')
 
-@pytest.mark.skip(reason='need python conductor')
 class TestMask:
 
     def test_let_let_mask(self) :
-        activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 }, composer.mask('() => x'))))
+        activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 }, composer.mask(get_x))), {})
         assert activation['response']['result'] == { 'value': 42 }
 
     def test_let_mask_let(self) :
-        activation = invoke(composer.let({ 'x': 42 }, composer.mask(composer.let({ 'x': 69 }, '() => x'))))
+        activation = invoke(composer.let({ 'x': 42 }, composer.mask(composer.let({ 'x': 69 }, get_x))), {})
         assert activation['response']['result'] == { 'value': 69 }
 
     def test_let_let_try_mask(self) :
         activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 },
-            composer.do(composer.mask('() => x'), '() => { }'))))
+            composer.do(composer.mask(get_x), noop))))
         assert activation['response']['result'] == { 'value': 42 }
 
     def test_let_let_let_mask(self) :
         activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 },
-            composer.let({ 'x': -1 }, composer.mask('() => x')))))
+            composer.let({ 'x': -1 }, composer.mask(get_x)))))
         assert activation['response']['result'] == { 'value': 69 }
 
     def test_let_let_let_mask_mask(self) :
         activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 },
-            composer.let({ 'x': -1 }, composer.mask(composer.mask('() => x'))))))
+            composer.let({ 'x': -1 }, composer.mask(composer.mask(get_x))))), {})
         assert activation['response']['result'] == { 'value': 42 }
 
     def test_let_let_mask_let_mask(self) :
         activation = invoke(composer.let({ 'x': 42 }, composer.let({ 'x': 69 },
-            composer.mask(composer.let({ 'x': -1 }, composer.mask('() => x'))))))
+            composer.mask(composer.let({ 'x': -1 }, composer.mask(get_x))))))
         assert activation['response']['result'] == { 'value': 42 }
 
 class TestRetain:
@@ -315,20 +337,16 @@
         activation = invoke(composer.retain('TripleAndIncrement'), { 'n': 3 })
         assert activation['response']['result'] == { 'params': { 'n': 3 }, 'result': { 'n': 10 } }
 
-    @pytest.mark.skip(reason='need python conductor')
     def test_throw_error(self) :
         try:
-            activation = invoke(composer.retain('() => ({ error: "foo" })'), { 'n': 3 })
+            invoke(composer.retain(set_error), { 'n': 3 })
             assert False
-        except composer.ComposerError as error:
-            assert error.error.response.result == { 'error': 'foo' }
+        except Exception as err:
+            assert err.error['response']['result'] == { 'error': 'foo' }
 
-    @pytest.mark.skip(reason='need python conductor')
     def test_catch_error(self) :
-        try:
-            activation = invoke(composer.retain_catch('() => ({ error: "foo" })'), { 'n': 3 })
-        except Exception as activation:
-            assert activation['response']['result'] == { 'params': { 'n': 3 }, 'result': { 'error': 'foo' } }
+        activation = invoke(composer.retain_catch(set_error), { 'n': 3 })
+        assert activation['response']['result'] == { 'params': { 'n': 3 }, 'result': { 'error': 'foo' } }
 
 class TestRepeat:
 
@@ -343,24 +361,27 @@
         except composer.ComposerError as error:
             assert error.message.startswith('Invalid argument')
 
+def retry_test(env, args):
+    x = env['x']
+    env['x'] -= 1
+    return { 'error': 'foo' } if x > 0 else 42
+
 class TestRetry:
 
-    @pytest.mark.skip(reason='need python conductor')
     def test_success(self) :
-        activation = invoke(composer.let({ 'x': 2 }, composer.retry(2, '() => x-- > 0 ? { error: "foo" } : 42')))
+        activation = invoke(composer.let({ 'x': 2 }, composer.retry(2, retry_test)))
         assert activation['response']['result'] == { 'value': 42 }
 
-    @pytest.mark.skip(reason='need python conductor')
     def test_failure(self) :
         try:
-            activation = invoke(composer.let({ 'x': 2 }, composer.retry(1, '() => x-- > 0 ? { error: "foo" } : 42')))
+            invoke(composer.let({ 'x': 2 }, composer.retry(1, retry_test)))
             assert False
-        except Exception as activation:
-            assert activation.error.response.result.error, 'foo'
+        except composer.ComposerError as err:
+            assert err.error.response.result.error, 'foo'
 
     def test_invalid_argument(self) :
         try:
             invoke(composer.retry('foo'))
             assert False
-        except Exception as error:
+        except composer.ComposerError as error:
             assert error.message.startswith('Invalid argument')
\ No newline at end of file