| Index: recipe_engine/loader.py
|
| diff --git a/recipe_engine/loader.py b/recipe_engine/loader.py
|
| index e8b67258781b23872108043f4f193f2370d3c147..e5adefb7e6825f34afe78752fe4184a51e45728c 100644
|
| --- a/recipe_engine/loader.py
|
| +++ b/recipe_engine/loader.py
|
| @@ -25,7 +25,9 @@ class NoSuchRecipe(Exception):
|
| class RecipeScript(object):
|
| """Holds dict of an evaluated recipe script."""
|
|
|
| - def __init__(self, recipe_dict):
|
| + def __init__(self, recipe_dict, name):
|
| + self.name = name
|
| +
|
| # Let each property object know about the property name.
|
| recipe_dict['PROPERTIES'] = {
|
| name: value.bind(name, BoundProperty.RECIPE_PROPERTY, name)
|
| @@ -50,6 +52,8 @@ class RecipeScript(object):
|
| return_schema = getattr(self, 'RETURN_SCHEMA', None)
|
|
|
| if return_schema:
|
| + if not recipe_result:
|
| + raise ValueError("Recipe %s did not return a value." % self.name)
|
| return recipe_result.as_jsonish(True)
|
| else:
|
| return None
|
| @@ -66,7 +70,10 @@ class RecipeScript(object):
|
|
|
| script_vars['LOADED_DEPS'] = universe.deps_from_spec(
|
| script_vars.get('DEPS', []))
|
| - return cls(script_vars)
|
| +
|
| + # 'a/b/c/my_name.py' -> my_name
|
| + name = os.path.basename(script_path).split('.')[0]
|
| + return cls(script_vars, name)
|
|
|
|
|
| class Dependency(object):
|
| @@ -131,9 +138,14 @@ class PackageDependency(PathDependency):
|
|
|
|
|
| class RecipeUniverse(object):
|
| - def __init__(self, package_deps):
|
| + def __init__(self, package_deps, config_file):
|
| self._loaded = {}
|
| self._package_deps = package_deps
|
| + self._config_file = config_file
|
| +
|
| + @property
|
| + def config_file(self):
|
| + return self._config_file
|
|
|
| @property
|
| def module_dirs(self):
|
| @@ -406,6 +418,36 @@ class DependencyMapper(object):
|
| self._instances[mod] = self._instantiator(mod, deps_dict)
|
| return self._instances[mod]
|
|
|
| +def _invoke_with_properties(callable_obj, all_props, prop_defs, arg_names,
|
| + **additional_args):
|
| + """Internal version of invoke_with_properties.
|
| +
|
| + The main difference is it gets passed the argument names as `arg_names`.
|
| + This allows us to reuse this logic elsewhere, without defining a fake function
|
| + which has arbitrary argument names.
|
| + """
|
| + for name, prop in prop_defs.items():
|
| + if not isinstance(prop, BoundProperty):
|
| + raise ValueError(
|
| + "You tried to invoke {} with an unbound Property {} named {}".format(
|
| + callable, prop, name))
|
| +
|
| + props = []
|
| + for arg in arg_names:
|
| + if arg in additional_args:
|
| + props.append(additional_args.pop(arg))
|
| + continue
|
| +
|
| + if arg not in prop_defs:
|
| + raise UndefinedPropertyException(
|
| + "Missing property definition for '{}'.".format(arg))
|
| +
|
| + prop = prop_defs[arg]
|
| + props.append(prop.interpret(all_props.get(
|
| + prop.param_name, PROPERTY_SENTINEL)))
|
| +
|
| + return callable_obj(*props, **additional_args)
|
| +
|
| def invoke_with_properties(callable_obj, all_props, prop_defs,
|
| **additional_args):
|
| """
|
| @@ -428,39 +470,21 @@ def invoke_with_properties(callable_obj, all_props, prop_defs,
|
| """
|
| # Check that we got passed BoundProperties, and not Properties
|
|
|
| - for name, prop in prop_defs.items():
|
| - if not isinstance(prop, BoundProperty):
|
| - raise ValueError(
|
| - "You tried to invoke {} with an unbound Property {} named {}".format(
|
| - callable, prop, name))
|
|
|
| # To detect when they didn't specify a property that they have as a
|
| # function argument, list the arguments, through inspection,
|
| # and then comparing this list to the provided properties. We use a list
|
| # instead of a dict because getargspec returns a list which we would have to
|
| # convert to a dictionary, and the benefit of the dictionary is pretty small.
|
| - props = []
|
| if inspect.isclass(callable_obj):
|
| arg_names = inspect.getargspec(callable_obj.__init__).args
|
|
|
| arg_names.pop(0)
|
| else:
|
| arg_names = inspect.getargspec(callable_obj).args
|
| + return _invoke_with_properties(callable_obj, all_props, prop_defs, arg_names,
|
| + **additional_args)
|
|
|
| - for arg in arg_names:
|
| - if arg in additional_args:
|
| - props.append(additional_args.pop(arg))
|
| - continue
|
| -
|
| - if arg not in prop_defs:
|
| - raise UndefinedPropertyException(
|
| - "Missing property definition for '{}'.".format(arg))
|
| -
|
| - prop = prop_defs[arg]
|
| - props.append(prop.interpret(all_props.get(
|
| - prop.param_name, PROPERTY_SENTINEL)))
|
| -
|
| - return callable_obj(*props, **additional_args)
|
|
|
| def create_recipe_api(toplevel_deps, engine, test_data=DisabledTestData()):
|
| def instantiator(mod, deps):
|
|
|