def _assign_dynamic_config_values(self, schema, config, parent_keys=None):
        """
        Assign dynamic config value for a particular config item if the ite utilizes a Jinja
        expression for dynamic config values.

        Note: This method mutates config argument in place.

        :rtype: ``dict``
        """
        parent_keys = parent_keys or []

        config_is_dict = isinstance(config, dict)
        config_is_list = isinstance(config, list)
        iterator = six.iteritems(config) if config_is_dict else enumerate(config)

        # config_item_key - if config_is_dict then this is the key in the dictionary
        #                   if config_is_list then this is the index of them item
        # config_item_value - the value of the key/index for the current item
        for config_item_key, config_item_value in iterator:
            if config_is_dict:
                # different schema for each key/value pair
                schema_item = schema.get(config_item_key, {})
            if config_is_list and isinstance(schema, list):
                # positional schema for list items
                try:
                    schema_item = schema[config_item_key]
                except IndexError:
                    schema_item = {}
            elif config_is_list:
                # same schema is shared between every item in the list
                schema_item = schema

            is_dictionary = isinstance(config_item_value, dict)
            is_list = isinstance(config_item_value, list)

            # pass a copy of parent_keys so the loop doesn't add sibling keys
            current_keys = parent_keys + [str(config_item_key)]

            # Inspect nested object properties
            if is_dictionary:
                properties_schema = self._get_object_properties_schema(
                    schema_item,
                    object_keys=config_item_value.keys(),
                )
                self._assign_dynamic_config_values(
                    schema=properties_schema,
                    config=config[config_item_key],
                    parent_keys=current_keys,
                )
            # Inspect nested list items
            elif is_list:
                items_schema = self._get_array_items_schema(
                    schema_item,
                    items_count=len(config[config_item_key]),
                )
                self._assign_dynamic_config_values(
                    schema=items_schema,
                    config=config[config_item_key],
                    parent_keys=current_keys,
                )
            else:
                is_jinja_expression = jinja_utils.is_jinja_expression(
                    value=config_item_value
                )

                if is_jinja_expression:
                    # Resolve / render the Jinja template expression
                    full_config_item_key = ".".join(current_keys)
                    value = self._get_datastore_value_for_expression(
                        key=full_config_item_key,
                        value=config_item_value,
                        config_schema_item=schema_item,
                    )

                    config[config_item_key] = value
                else:
                    # Static value, no resolution needed
                    config[config_item_key] = config_item_value

        return config

        Assign dynamic config value for a particular config item if the ite utilizes a Jinja
        expression for dynamic config values.

        Note: This method mutates config argument in place.

        :rtype: ``dict``
        
st2common/st2common/util/config_loader.py