コード例 #1
0
 def _try_replace_pattern(to_replace):
     try:
         # A pattern requires us to look up the data located at
         # to_replace[jsonpath] and then figure out what
         # re.match(to_replace[jsonpath], pattern) is (in pseudocode).
         # Raise an exception in case the path isn't present in the
         # to_replace and a pattern has been provided since it is
         # otherwise impossible to do the look-up.
         replacement = re.sub(pattern, six.text_type(value_copy),
                              to_replace)
     except TypeError as e:
         LOG.error(
             'Failed to substitute the value %s into %s '
             'using pattern %s. Details: %s', six.text_type(value_copy),
             to_replace, pattern, six.text_type(e))
         raise errors.MissingDocumentPattern(jsonpath=jsonpath,
                                             pattern=pattern)
     return replacement
コード例 #2
0
def jsonpath_replace(data, value, jsonpath, pattern=None):
    """Update value in ``data`` at the path specified by ``jsonpath``.

    If the nested path corresponding to ``jsonpath`` isn't found in ``data``,
    the path is created as an empty ``{}`` for each sub-path along the
    ``jsonpath``.

    :param data: The `data` section of a document.
    :param value: The new value for ``data[jsonpath]``.
    :param jsonpath: A multi-part key that references a nested path in
        ``data``.
    :param pattern: A regular expression pattern.
    :returns: Updated value at ``data[jsonpath]``.
    :raises: MissingDocumentPattern if ``pattern`` is not None and
        ``data[jsonpath]`` doesn't exist.

    Example::

        doc = {
            'data': {
                'some_url': http://admin:INSERT_PASSWORD_HERE@svc-name:8080/v1
            }
        }
        secret = 'super-duper-secret'
        path = '$.some_url'
        pattern = 'INSERT_[A-Z]+_HERE'
        replaced_data = utils.jsonpath_replace(
            doc['data'], secret, path, pattern)
        # The returned URL will look like:
        # http://admin:super-duper-secret@svc-name:8080/v1
        doc['data'].update(replaced_data)
    """
    data = data.copy()
    if jsonpath.startswith('.'):
        jsonpath = '$' + jsonpath

    def _do_replace():
        p = jsonpath_ng.parse(jsonpath)
        p_to_change = p.find(data)

        if p_to_change:
            _value = value
            if pattern:
                to_replace = p_to_change[0].value
                # `value` represents the value to inject into `to_replace` that
                # matches the `pattern`.
                try:
                    _value = re.sub(pattern, value, to_replace)
                except TypeError:
                    _value = None
            return p.update(data, _value)

    result = _do_replace()
    if result:
        return result

    # A pattern requires us to look up the data located at data[jsonpath]
    # and then figure out what re.match(data[jsonpath], pattern) is (in
    # pseudocode). But raise an exception in case the path isn't present in the
    # data and a pattern has been provided since it is impossible to do the
    # look up.
    if pattern:
        raise errors.MissingDocumentPattern(
            data=data, path=jsonpath, pattern=pattern)

    # However, Deckhand should be smart enough to create the nested keys in the
    # data if they don't exist and a pattern isn't required.
    d = data
    for path in jsonpath.split('.')[1:]:
        if path not in d:
            d.setdefault(path, {})
        d = d.get(path)

    return _do_replace()
コード例 #3
0
def jsonpath_replace(data, value, jsonpath, pattern=None):
    """Update value in ``data`` at the path specified by ``jsonpath``.

    If the nested path corresponding to ``jsonpath`` isn't found in ``data``,
    the path is created as an empty ``{}`` for each sub-path along the
    ``jsonpath``.

    :param data: The `data` section of a document.
    :param value: The new value for ``data[jsonpath]``.
    :param jsonpath: A multi-part key that references a nested path in
        ``data``. Must begin with "." (without quotes).
    :param pattern: A regular expression pattern.
    :returns: Updated value at ``data[jsonpath]``.
    :raises: MissingDocumentPattern if ``pattern`` is not None and
        ``data[jsonpath]`` doesn't exist.
    :raises ValueError: If ``jsonpath`` doesn't begin with "."

    Example::

        doc = {
            'data': {
                'some_url': http://admin:INSERT_PASSWORD_HERE@svc-name:8080/v1
            }
        }
        secret = 'super-duper-secret'
        path = '$.some_url'
        pattern = 'INSERT_[A-Z]+_HERE'
        replaced_data = utils.jsonpath_replace(
            doc['data'], secret, path, pattern)
        # The returned URL will look like:
        # http://admin:super-duper-secret@svc-name:8080/v1
        doc['data'].update(replaced_data)
    """
    data = copy.copy(data)
    value = copy.copy(value)

    jsonpath = _normalize_jsonpath(jsonpath)

    if not jsonpath == '$' and not jsonpath.startswith('$.'):
        LOG.error('The provided jsonpath %s does not begin with "." or "$"',
                  jsonpath)
        raise ValueError('The provided jsonpath %s does not begin with "." '
                         'or "$"' % jsonpath)

    def _do_replace():
        p = _jsonpath_parse_cache(jsonpath)
        p_to_change = p.find(data)

        if p_to_change:
            new_value = value
            if pattern:
                to_replace = p_to_change[0].value
                # `new_value` represents the value to inject into `to_replace`
                # that matches the `pattern`.
                try:
                    new_value = re.sub(pattern, str(value), to_replace)
                except TypeError as e:
                    with excutils.save_and_reraise_exception():
                        LOG.error(
                            'Failed to substitute the value %s into %s '
                            'using pattern %s. Details: %s', str(value),
                            to_replace, pattern, six.text_type(e))
            return p.update(data, new_value)

    result = _do_replace()
    if result:
        return result

    # A pattern requires us to look up the data located at data[jsonpath]
    # and then figure out what re.match(data[jsonpath], pattern) is (in
    # pseudocode). But raise an exception in case the path isn't present in the
    # data and a pattern has been provided since it is impossible to do the
    # look-up.
    if pattern:
        raise errors.MissingDocumentPattern(path=jsonpath, pattern=pattern)

    # However, Deckhand should be smart enough to create the nested keys in the
    # data if they don't exist and a pattern isn't required.
    _populate_data_with_attributes(jsonpath, data)
    return _do_replace()