Helper for getting a documentation data file paths.

    Args:
        fn (str): Name of the file to retrieve the full path for.
        root (str): Optional root path to look for a docdata in.

    Notes:
        Defaults to looking for the ``docdata`` directory in the current
        working directory. This behavior works fine for notebooks nested
        in the docs directory of synapse; but this root directory that
        is looked for may be overridden by providing an alternative root.

    Returns:
        str: A file path.

    Raises:
        ValueError if the file does not exist or directory traversal attempted..

def getDocPath(fn, root=None):
    '''
    Helper for getting a documentation data file paths.

    Args:
        fn (str): Name of the file to retrieve the full path for.
        root (str): Optional root path to look for a docdata in.

    Notes:
        Defaults to looking for the ``docdata`` directory in the current
        working directory. This behavior works fine for notebooks nested
        in the docs directory of synapse; but this root directory that
        is looked for may be overridden by providing an alternative root.

    Returns:
        str: A file path.

    Raises:
        ValueError if the file does not exist or directory traversal attempted..
    '''
    cwd = pathlib.Path(os.getcwd())
    if root:
        cwd = pathlib.Path(root)
    # Walk up a directory until you find '...d./data'
    while True:
        dpath = cwd.joinpath('docdata')
        if dpath.is_dir():
            break
        parent = cwd.parent
        if parent == cwd:
            raise ValueError(f'Unable to find data directory from {os.getcwd()}.')
        cwd = parent

    # Protect against traversal
    fpath = os.path.abspath(os.path.join(dpath.as_posix(), fn))
    if not fpath.startswith(dpath.as_posix()):
        raise ValueError(f'Path escaping detected: {fn}')

    # Existence
    if not os.path.isfile(fpath):
        raise ValueError(f'File does not exist: {fn}')

    return fpath