Ejemplo n.º 1
0
def match_path_to_api_path(path_definitions,
                           target_path,
                           base_path='',
                           context=None):
    """
    Match a request or response path to one of the api paths.

    Anything other than exactly one match is an error condition.
    """
    if context is None:
        context = {}
    assert isinstance(context, collections.Mapping)
    if target_path.startswith(base_path):
        target_path = target_path[len(base_path):]
        # Convert all of the api paths into Path instances for easier regex matching.
        paths = {
            p: path_to_regex(
                api_path=p,
                path_parameters=extract_path_parameters(v),
                operation_parameters=extract_operation_parameters(v),
                context=context,
            )
            for p, v in path_definitions.items()
        }

        matching_api_paths = [(p, r.match(target_path))
                              for p, r in paths.items()
                              if r.match(target_path)]
    else:
        matching_api_paths = []

    if not matching_api_paths:
        raise LookupError(
            MESSAGES['path']['no_matching_paths_found'].format(target_path))
    elif len(matching_api_paths) > 1:
        # TODO: This area needs improved logic.
        # We check to see if any of the matched paths is longers than
        # the others.  If so, we *assume* it is the correct match.  This is
        # going to be prone to false positives. in certain cases.
        matches_by_path_size = collections.defaultdict(list)
        for path, match in matching_api_paths:
            matches_by_path_size[len(path)].append(path)
        longest_match = max(matches_by_path_size.keys())
        if len(matches_by_path_size[longest_match]) == 1:
            return matches_by_path_size[longest_match][0]
        raise MultiplePathsFound(
            MESSAGES['path']['multiple_paths_found'].format(
                target_path,
                [v[0] for v in matching_api_paths],
            ))
    else:
        return matching_api_paths[0][0]
Ejemplo n.º 2
0
def match_path_to_api_path(path_definitions,
                           target_path,
                           base_path='',
                           context=None):
    """
    Match a request or response path to one of the api paths.

    Anything other than exactly one match is an error condition.
    """
    if context is None:
        context = {}
    assert isinstance(context, Mapping)
    if target_path.startswith(base_path):
        # Convert all of the api paths into Path instances for easier regex
        # matching.
        normalized_target_path = re.sub(NORMALIZE_SLASH_REGEX, '/',
                                        target_path)
        matching_api_paths = list()
        matching_api_paths_regex = list()
        for p, v in path_definitions.items():
            # Doing this to help with case where we might have base_path
            # being just /, and then the path starts with / as well.
            full_path = re.sub(NORMALIZE_SLASH_REGEX, '/', base_path + p)
            r = path_to_regex(
                api_path=full_path,
                path_parameters=extract_path_parameters(v),
                operation_parameters=extract_operation_parameters(v),
                context=context,
            )
            if full_path == normalized_target_path:
                matching_api_paths.append(p)
            elif r.match(normalized_target_path):
                matching_api_paths_regex.\
                    append((p, r.match(normalized_target_path)))

        # Keep it consistent with the previous behavior
        target_path = target_path[len(base_path):]
    else:
        matching_api_paths = []
        matching_api_paths_regex = []

    if not matching_api_paths and not matching_api_paths_regex:
        fstr = MESSAGES['path']['no_matching_paths_found'].format(target_path)
        raise LookupError(fstr)
    elif len(matching_api_paths) == 1:
        return matching_api_paths[0]
    elif len(matching_api_paths) > 1:
        raise MultiplePathsFound(
            MESSAGES['path']['multiple_paths_found'].format(
                target_path,
                [v[0] for v in matching_api_paths],
            ))
    elif len(matching_api_paths_regex) == 1:
        return matching_api_paths_regex[0][0]
    elif len(matching_api_paths_regex) > 1:
        # TODO: This area needs improved logic.
        # We check to see if any of the matched paths is longers than
        # the others.  If so, we *assume* it is the correct match.  This is
        # going to be prone to false positives. in certain cases.
        matches_by_path_size = collections.defaultdict(list)
        for path, match in matching_api_paths_regex:
            matches_by_path_size[len(path)].append(path)
        longest_match = max(matches_by_path_size.keys())
        if len(matches_by_path_size[longest_match]) == 1:
            return matches_by_path_size[longest_match][0]
        raise MultiplePathsFound(
            MESSAGES['path']['multiple_paths_found'].format(
                target_path,
                [v[0] for v in matching_api_paths_regex],
            ))
    else:
        return matching_api_paths_regex[0][0]