def test_parse_string_in_quotes_input(self):
        tests = [('x="true"', [{
            'x': "true"
        }]), ('y="True"', [{
            'y': "True"
        }]), ('c="TRUE"', [{
            'c': "TRUE"
        }]), ('d="123"', [{
            'd': '123'
        }]), ('e="abcde"', [{
            'e': 'abcde'
        }]), ('f=""', [{
            'f': ''
        }]), ("x='false'", [{
            'x': 'false'
        }]), ("y='False'", [{
            'y': 'False'
        }]), ("c='FALSE'", [{
            'c': 'FALSE'
        }]), ("d='123'", [{
            'd': '123'
        }]), ("e='abcde'", [{
            'e': 'abcde'
        }]), ("f=''", [{
            'f': ''
        }])]

        for s, d in tests:
            self.assertListEqual(args_util.parse_inline_params(s), d)
    def test_parse_multiple(self):
        tests = [('x="abc" y="def"', [{
            'x': 'abc'
        }, {
            'y': 'def'
        }]), ('y="def" x="abc"', [{
            'y': 'def'
        }, {
            'x': 'abc'
        }]), ('x="abc", y="def"', [{
            'x': 'abc'
        }, {
            'y': 'def'
        }]), ('y="def", x="abc"', [{
            'y': 'def'
        }, {
            'x': 'abc'
        }]), ('x="abc"; y="def"', [{
            'x': 'abc'
        }, {
            'y': 'def'
        }]), ('y="def"; x="abc"', [{
            'y': 'def'
        }, {
            'x': 'abc'
        }])]

        for s, d in tests:
            self.assertListEqual(args_util.parse_inline_params(s), d)
    def test_parse_expression(self):
        tests = [('x=<% $.abc %>', {
            'x': '<% $.abc %>'
        }), ('x={{ _.abc }}', {
            'x': '{{ _.abc }}'
        })]

        for s, d in tests:
            self.assertDictEqual(args_util.parse_inline_params(s)[0], d)
예제 #4
0
    def __init__(self, *args, **kwargs):
        super(TaskSpec, self).__init__(*args, **kwargs)

        action_spec = getattr(self, 'action', str())
        input_spec = args_util.parse_inline_params(action_spec, preserve_order=False)

        if input_spec:
            self.action = action_spec[:action_spec.index(' ')]
            self.input = input_spec
예제 #5
0
    def __init__(self, *args, **kwargs):
        super(TaskTransitionSpec, self).__init__(*args, **kwargs)

        publish_spec = getattr(self, 'publish', None)

        if publish_spec and isinstance(publish_spec, six.string_types):
            self.publish = args_util.parse_inline_params(publish_spec or str())

        do_spec = getattr(self, 'do', None)

        if not do_spec:
            self.do = 'continue'
    def test_parse_bool_input(self):
        tests = [('x=true', [{
            'x': True
        }]), ('y=True', [{
            'y': True
        }]), ('c=TRUE', [{
            'c': True
        }]), ('x=false', [{
            'x': False
        }]), ('y=False', [{
            'y': False
        }]), ('c=FALSE', [{
            'c': False
        }])]

        for s, d in tests:
            self.assertListEqual(args_util.parse_inline_params(s), d)
    def test_parse_combination(self):
        s = 'i=123 j="abc" k=true x=<% $.abc %> y={{ _.abc }} z=\'{\"a\": 1}\''

        d = [{
            'i': 123
        }, {
            'j': 'abc'
        }, {
            'k': True
        }, {
            'x': '<% $.abc %>'
        }, {
            'y': '{{ _.abc }}'
        }, {
            'z': {
                'a': 1
            }
        }]

        self.assertListEqual(args_util.parse_inline_params(s), d)
    def test_parse_basic(self):
        tests = [('x=null', {
            'x': None
        }), ('x=123', {
            'x': 123
        }), ('x=-123', {
            'x': -123
        }), ('x=0.123', {
            'x': 0.123
        }), ('x=-0.123', {
            'x': -0.123
        }), ('x=true', {
            'x': True
        }), ('x=false', {
            'x': False
        }), ('x="abc"', {
            'x': 'abc'
        }), ("x='abc'", {
            'x': 'abc'
        })]

        for s, d in tests:
            self.assertDictEqual(args_util.parse_inline_params(s)[0], d)
    def test_parse_dictionary(self):
        tests = [('x=\'{\"a\": 1}\'', {'x': {'a': 1}})]

        for s, d in tests:
            self.assertDictEqual(args_util.parse_inline_params(s)[0], d)
 def test_parse_other_types(self):
     self.assertListEqual(args_util.parse_inline_params(123), [])
     self.assertListEqual(args_util.parse_inline_params(True), [])
     self.assertListEqual(args_util.parse_inline_params([1, 2, 3]), [])
     self.assertListEqual(args_util.parse_inline_params({'a': 123}), [])
 def test_parse_null_type(self):
     self.assertListEqual(args_util.parse_inline_params(None), [])
 def test_parse_empty_string(self):
     self.assertListEqual(args_util.parse_inline_params(str()), [])
예제 #13
0
    def inspect_context(self, parent=None):
        if parent and not parent.get("spec_path", None):
            raise ValueError("Parent context is missing spec path.")

        if parent and not parent.get("schema_path", None):
            raise ValueError("Parent context is missing schema path.")

        def decorate_ctx_var(variable, spec_path, schema_path):
            return {
                "type": variable[0],
                "expression": variable[1],
                "name": variable[2],
                "spec_path": spec_path,
                "schema_path": schema_path,
            }

        def decorate_ctx_var_error(var, msg):
            error = expr_util.format_error(
                var["type"], var["expression"], msg, var["spec_path"], var["schema_path"]
            )

            return error

        def get_ctx_inputs(prop_name, prop_value):
            ctx_inputs = []

            # By default, context inputs support only dictionary,
            # list of single item dictionaries, or string spec_types.
            if isinstance(prop_value, dict):
                ctx_inputs = list(prop_value.keys())
            elif isinstance(prop_value, list):
                for prop_value_item in prop_value:
                    if isinstance(prop_value_item, six.string_types):
                        ctx_inputs.append(prop_value_item)
                    elif isinstance(prop_value_item, dict) and len(prop_value_item) == 1:
                        ctx_inputs.extend(list(prop_value_item.keys()))
            elif isinstance(prop_value, six.string_types):
                ctx_inputs.append(prop_value)

            return ctx_inputs

        def inspect_ctx(prop_name, prop_value, spec_path, schema_path, rolling_ctx, errors):
            ctx_vars = []

            for var in expr_base.extract_vars(prop_value):
                ctx_vars.append(decorate_ctx_var(var, spec_path, schema_path))

            for ctx_var in ctx_vars:
                if ctx_var["name"].startswith("__"):
                    err_msg = (
                        'Variable "%s" that is prefixed with double underscores is considered '
                        "a private variable and cannot be referenced." % ctx_var["name"]
                    )
                    errors.append(decorate_ctx_var_error(ctx_var, err_msg))

                if ctx_var["name"] not in rolling_ctx:
                    err_msg = 'Variable "%s" is referenced before assignment.' % ctx_var["name"]
                    errors.append(decorate_ctx_var_error(ctx_var, err_msg))

            if prop_name in self._context_inputs:
                updated_ctx = get_ctx_inputs(prop_name, prop_value)
                rolling_ctx = list(set(rolling_ctx + updated_ctx))

            return rolling_ctx, errors

        errors = []
        parent_ctx = parent.get("ctx", []) if parent else []
        rolling_ctx = list(set(parent_ctx))

        for prop_name in self._context_evaluation_sequence:
            prop_value = getattr(self, prop_name)

            if not prop_value:
                continue

            spec_path = self.get_spec_path(prop_name, parent=parent)
            schema_path = self.get_schema_path(prop_name, parent=parent)

            # Pass the inspection downstream if value is a spec.
            if isinstance(prop_value, Spec):
                item_parent = {
                    "ctx": rolling_ctx,
                    "spec_path": spec_path,
                    "schema_path": schema_path,
                }

                result = prop_value.inspect_context(parent=item_parent)
                errors.extend(result[0])
                rolling_ctx = list(set(rolling_ctx + result[1]))

                continue

            # Parse inline parameters from value if value is a string.
            if isinstance(prop_value, six.string_types):
                inline_params = args_util.parse_inline_params(prop_value)

                if inline_params:
                    prop_value = inline_params

            # Preserve evaluation order if value is a list.
            if isinstance(prop_value, list):
                for i in range(0, len(prop_value)):
                    rolling_ctx, errors = inspect_ctx(
                        prop_name,
                        prop_value[i],
                        spec_path + "[" + str(i) + "]",
                        schema_path,
                        rolling_ctx,
                        errors,
                    )

                continue

            # Otherwise evaluate the value as is.
            rolling_ctx, errors = inspect_ctx(
                prop_name, prop_value, spec_path, schema_path, rolling_ctx, errors
            )

        return (sorted(errors, key=lambda x: x["spec_path"]), rolling_ctx)
예제 #14
0
    def inspect_context(self, parent=None):
        if parent and not parent.get('spec_path', None):
            raise ValueError('Parent context is missing spec path.')

        if parent and not parent.get('schema_path', None):
            raise ValueError('Parent context is missing schema path.')

        def decorate_ctx_var(variable, spec_path, schema_path):
            return {
                'type': variable[0],
                'expression': variable[1],
                'name': variable[2],
                'spec_path': spec_path,
                'schema_path': schema_path
            }

        def decorate_ctx_var_error(var):
            error = expr_utils.format_error(
                var['type'], var['expression'],
                'Variable "%s" is referenced before assignment.' % var['name'],
                var['spec_path'], var['schema_path'])

            return error

        def get_ctx_inputs(prop_name, prop_value):
            ctx_inputs = []

            # By default, context inputs support only dictionary,
            # list of single item dictionaries, or string types.
            if isinstance(prop_value, dict):
                ctx_inputs = list(prop_value.keys())
            elif isinstance(prop_value, list):
                for prop_value_item in prop_value:
                    if isinstance(prop_value_item, six.string_types):
                        ctx_inputs.append(prop_value_item)
                    elif isinstance(prop_value_item,
                                    dict) and len(prop_value_item) == 1:
                        ctx_inputs.extend(list(prop_value_item.keys()))
            elif isinstance(prop_value, six.string_types):
                ctx_inputs.append(prop_value)

            return ctx_inputs

        def inspect_ctx(prop_name, prop_value, spec_path, schema_path,
                        rolling_ctx, errors):
            ctx_vars = []

            for var in expr.extract_vars(prop_value):
                ctx_vars.append(decorate_ctx_var(var, spec_path, schema_path))

            for ctx_var in ctx_vars:
                if ctx_var['name'] not in rolling_ctx:
                    errors.append(decorate_ctx_var_error(ctx_var))

            if prop_name in self._context_inputs:
                updated_ctx = get_ctx_inputs(prop_name, prop_value)
                rolling_ctx = list(set(rolling_ctx + updated_ctx))

            return rolling_ctx, errors

        errors = []
        parent_ctx = parent.get('ctx', []) if parent else []
        rolling_ctx = list(set(parent_ctx))

        for prop_name in self._context_evaluation_sequence:
            prop_value = getattr(self, prop_name)

            if not prop_value:
                continue

            spec_path = self.get_spec_path(prop_name, parent=parent)
            schema_path = self.get_schema_path(prop_name, parent=parent)

            # Pass the inspection downstream if value is a spec.
            if isinstance(prop_value, Spec):
                item_parent = {
                    'ctx': rolling_ctx,
                    'spec_path': spec_path,
                    'schema_path': schema_path
                }

                result = prop_value.inspect_context(parent=item_parent)
                errors.extend(result[0])
                rolling_ctx = list(set(rolling_ctx + result[1]))

                continue

            # Parse inline parameters from value if value is a string.
            if isinstance(prop_value, six.string_types):
                inline_params = args_utils.parse_inline_params(prop_value)

                if inline_params:
                    prop_value = inline_params

            # Preserve evaluation order if value is a list.
            if isinstance(prop_value, list):
                for i in range(0, len(prop_value)):
                    rolling_ctx, errors = inspect_ctx(
                        prop_name, prop_value[i],
                        spec_path + '[' + str(i) + ']', schema_path,
                        rolling_ctx, errors)

                continue

            # Otherwise evaluate the value as is.
            rolling_ctx, errors = inspect_ctx(prop_name, prop_value, spec_path,
                                              schema_path, rolling_ctx, errors)

        return (sorted(errors, key=lambda x: x['spec_path']), rolling_ctx)