Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a first attempt at a glob file #854

Merged
merged 10 commits into from
May 2, 2019
63 changes: 49 additions & 14 deletions bindings/python/libs/client/glob_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,49 @@ def split_url(url):
return domain, path


def glob(pathname, raise_error=False):
def iglob(pathname, raise_error=False):
"""
Generates paths based on a wild-carded path, potentially via xrootd.

Multiple wild-cards can be present in the path.

Args:
pathname (str): The wild-carded path to be expanded.
raise_error (bool): Whether or not to let xrootd raise an error if
there's a problem. If False (default), and there's a problem for a
particular directory or file, then that will simply be skipped,
likely resulting in an empty list.

Yields:
(str): A single path that matches the wild-carded string
"""
# Let normal python glob try first
try_glob = gl.glob(pathname)
if try_glob:
return try_glob
generator = gl.iglob(pathname)
path = next(generator, None)
if path is not None:
yield path
for path in generator:
yield path
return

# Else try xrootd instead
return xrootd_glob(pathname, raise_error=raise_error)
for path in xrootd_iglob(pathname, raise_error=raise_error):
yield path


def xrootd_iglob(pathname, raise_error):
"""Handles the actual interaction with xrootd

def xrootd_glob(pathname, raise_error):
Provides a python generator over files that match the wild-card expression.
"""
# Split the pathname into a directory and basename
dirs, basename = os.path.split(pathname)

if gl.has_magic(dirs):
dirs = xrootd_glob(dirs)
dirs = list(xrootd_iglob(dirs, raise_error))
else:
dirs = [dirs]

files = []
for dirname in dirs:
host, path = split_url(dirname)
query = FileSystem(host)
Expand All @@ -84,11 +107,23 @@ def xrootd_glob(pathname, raise_error):
continue
if not fnmatch.fnmatchcase(filename, basename):
continue
files.append(os.path.join(dirname, filename))
yield os.path.join(dirname, filename)

return files


def iglob(pathname):
for name in glob(pathname):
yield name
def glob(pathname, raise_error=False):
"""
Creates a list of paths that match pathname.

Multiple wild-cards can be present in the path.

Args:
pathname (str): The wild-carded path to be expanded.
raise_error (bool): Whether or not to let xrootd raise an error if
there's a problem. If False (default), and there's a problem for a
particular directory or file, then that will simply be skipped,
likely resulting in an empty list.

Returns:
(str): A single path that matches the wild-carded string
"""
return list(iglob(pathname, raise_error=raise_error))
24 changes: 14 additions & 10 deletions bindings/python/tests/test_glob.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
import os
import glob as norm_glob
import XRootD.client.glob_funcs as glob
from pathlib2 import Path
Expand All @@ -16,17 +17,20 @@ def tmptree(tmpdir):
return tmpdir


@pytest.mark.parametrize("modify", [lambda x: x, lambda x: Path("root://localhost:/") / x])
def test_glob(tmptree, modify):
tmptree = modify(tmptree)
assert glob.glob(str(tmptree / "not-there")) == norm_glob.glob(str(tmptree / "not-there"))
assert len(glob.glob(str(tmptree / "not-there"))) == 0
assert len(glob.glob(str(tmptree / "not-there*"))) == 0
assert len(glob.glob(str(tmptree / "sub*"))) == 2
assert len(glob.glob(str(tmptree / "subdir1" / "*txt"))) == 3
assert len(glob.glob(str(tmptree / "subdir*" / "*txt"))) == 3
@pytest.mark.parametrize("prefix", ["", r"root://localhost:"])
def test_glob(tmptree, prefix):
tmptree = str(tmptree)
if prefix:
tmptree = prefix + tmptree
normal_glob_result = norm_glob.glob(os.path.join(tmptree, "not-there"))
assert glob.glob(os.path.join(tmptree, "not-there")) == normal_glob_result
assert len(glob.glob(os.path.join(tmptree, "not-there"))) == 0
assert len(glob.glob(os.path.join(tmptree, "not-there*"))) == 0
assert len(glob.glob(os.path.join(tmptree, "sub*"))) == 2
assert len(glob.glob(os.path.join(tmptree, "subdir1", "*txt"))) == 3
assert len(glob.glob(os.path.join(tmptree, "subdir*", "*txt"))) == 3

with pytest.raises(RuntimeError) as excinfo:
glob.glob(str(tmptree / "not-there"), raise_error=True)
glob.glob(os.path.join(tmptree, "not-there"), raise_error=True)
assert "[ERROR]" in str(excinfo.value)
assert str(tmptree) in str(excinfo.value)