Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This file is part of xrootdpyfs
# Copyright (C) 2015-2023 CERN.
# Copyright (C) 2015-2026 CERN.
#
# xrootdpyfs is free software; you can redistribute it and/or modify it under the
# terms of the Revised BSD License; see LICENSE file for more details.
Expand All @@ -24,5 +24,7 @@ recursive-include tests *.py
recursive-include tests *.html
recursive-include tests *.dat
recursive-include tests *.txt
recursive-include tests *.py
recursive-include .github/workflows *.yml
recursive-include xrootdpyfs *.py
include .git-blame-ignore-revs
12 changes: 2 additions & 10 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,6 @@ integration:
>>> fs.listdir("xrootdpyfs")
['test.txt']

Or, alternatively using the PyFilesystem opener (note the first
``import xrootdpyfs`` is required to ensure the XRootDPyFS opener is registered):

>>> import xrootdpyfs
>>> from fs.opener import open_fs
>>> fs = open_fs("root://localhost//tmp/")
>>> fs.listdir("xrootdpyfs")
['test.txt']

Reading files:

>>> f = fs.open("xrootdpyfs/test.txt")
Expand Down Expand Up @@ -98,7 +89,8 @@ running XRootD server:
.. code-block:: console

$ docker build --platform linux/amd64 -t xrootd --progress=plain .
$ docker run --platform linux/amd64 -h xrootdpyfs -it -v <absolute path to this project>:/code xrootd bash
$ docker run --platform linux/amd64 -h xrootdpyfs -it -v <absolute path to this project>:/code xrootd
docker run --platform linux/amd64 -h xrootdpyfs -it -v /Users/nico/workspace/cern/invenio/modules/xrootdpyfs:/code xrootd
[xrootdpyfs@xrootdpyfs code]$ xrootd

In another shell:
Expand Down
6 changes: 0 additions & 6 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ File interface
:members:
:undoc-members:

Opener
------
.. automodule:: xrootdpyfs.opener
:members:
:undoc-members:

Environment
-----------
.. automodule:: xrootdpyfs.env
Expand Down
13 changes: 3 additions & 10 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# This file is part of xrootdpyfs
# Copyright (C) 2015-2023 CERN.
# Copyright (C) 2015-2026 CERN.
#
# xrootdpyfs is free software; you can redistribute it and/or modify it under
# the terms of the Revised BSD License; see LICENSE file for more details.

[metadata]
name = xrootdpyfs
version = attr: xrootdpyfs.__version__
description = XRootDPyFS is a PyFilesystem interface for XRootD.
description = XRootDPyFS is a PyFilesystem interface for XRootD
long_description = file: README.rst, CHANGES.rst
keywords = xrootdpyfs
license = BSD
Expand All @@ -25,11 +25,9 @@ classifiers =
[options]
include_package_data = True
packages = find:
python_requires = >=3.6
python_requires = >=3.9
zip_safe = False
install_requires =
fs>=2.0.10,<3.0
# 5.6.0 breaks compatibility, needs fix
xrootd>=5.0.0,<6.0.0

[options.extras_require]
Expand All @@ -41,11 +39,6 @@ tests =
sphinx>=4.5.0
setuptools<82.0.0

[options.entry_points]
fs.opener =
root = xrootdpyfs.opener:XRootDPyOpener
roots = xrootdpyfs.opener:XRootDPyOpener

[aliases]
test = pytest

Expand Down
20 changes: 13 additions & 7 deletions tests/perf.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
import os
import pstats
import shutil
import subprocess
import tempfile
import time
from io import StringIO
from os.path import join

from fs.opener import open_fs
from XRootD import client

from xrootdpyfs.fs import XRootDPyFS


def teardown(tmppath):
"""Tear down performance test."""
Expand All @@ -40,19 +42,21 @@ def setup():
filepath = join(tmppath, filename)

# Create test file with random data
os.system("dd bs=1024 count={1} </dev/urandom >{0}".format(filepath, 1024 * 10))
subprocess.run(
["dd", "bs=1024", "count=10240", "if=/dev/urandom", f"of={filepath}"],
check=True,
)

return filename, tmppath, filepath


#
# Test methods
#
def read_pyfs_chunks(url, filename, mode="rb", chunksize=2097152, n=100):
def read_pyfs_chunks(fs, filename, mode="rb", chunksize=2097152, n=100):
"""Read a file in chunks."""
t1 = time.time()

fs = open_fs(url)
assert fs.exists(filename)
i = 0
while i < n:
Expand Down Expand Up @@ -111,12 +115,14 @@ def main():
n = 10
rooturl = "root://localhost/{0}".format(testfilepath)

print("osfs:", testfilepath, read_pyfs_chunks(tmppath, filename, n=n))
print("pyxrootd:", rooturl, read_pyxrootd_chunks(rooturl, n=n))
# print("osfs:", testfilepath, read_pyfs_chunks(tmppath, filename, n=n))
print("pyxrootd:", rooturl, read_pyxrootd_chunks(XRootDPyFS(rooturl), n=n))

pr = profile_start()
print(
"xrootdpyfs:", rooturl, read_pyfs_chunks(rooturl, filename, mode="rb-", n=n)
"xrootdpyfs:",
rooturl,
read_pyfs_chunks(XRootDPyFS(rooturl), filename, mode="rb-", n=n),
)
profile_end(pr)
finally:
Expand Down
12 changes: 6 additions & 6 deletions tests/test_fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@

import pytest
from conftest import mkurl
from fs import ResourceType
from fs.errors import (
from mock import Mock
from XRootD.client.responses import XRootDStatus

from xrootdpyfs import XRootDPyFile, XRootDPyFS
from xrootdpyfs.fs_utils.enums import ResourceType
from xrootdpyfs.fs_utils.errors import (
DestinationExists,
DirectoryNotEmpty,
FSError,
Expand All @@ -29,10 +33,6 @@
ResourceNotFound,
Unsupported,
)
from mock import Mock
from XRootD.client.responses import XRootDStatus

from xrootdpyfs import XRootDPyFile, XRootDPyFS
from xrootdpyfs.utils import spliturl


Expand Down
2 changes: 1 addition & 1 deletion tests/test_fs_extras.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

import pytest
from conftest import mkurl
from fs.errors import ResourceNotFound

from xrootdpyfs import XRootDPyFS
from xrootdpyfs.fs_utils.errors import ResourceNotFound


def test_readtext(tmppath):
Expand Down
22 changes: 0 additions & 22 deletions tests/test_opener.py

This file was deleted.

25 changes: 15 additions & 10 deletions tests/test_xrdfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,21 @@
import math
from os.path import join

import fs.path
import pytest
from conftest import mkurl
from fs import Seek
from fs.errors import InvalidPath, PathError, ResourceNotFound, Unsupported
from fs.opener import open_fs
from mock import Mock
from XRootD.client.responses import XRootDStatus

from xrootdpyfs import XRootDPyFile
from xrootdpyfs.fs import XRootDPyFS
from xrootdpyfs.fs_utils.enums import Seek
from xrootdpyfs.fs_utils.errors import (
InvalidPath,
PathError,
ResourceNotFound,
Unsupported,
)
from xrootdpyfs.fs_utils.path import dirname
from xrootdpyfs.utils import is_valid_path, is_valid_url


Expand Down Expand Up @@ -98,7 +103,7 @@ def get_bin_testfile(tmppath):
def get_file(fn, fp, tmppath):
path = join(tmppath, fp)
fpp = join(path, fn)
fs = open_fs(path)
fs = XRootDPyFS(path)
with fs.open(fn) as f:
fc = f.read()
return {"filename": fn, "dir": fp, "contents": fc, "full_path": fpp}
Expand All @@ -107,7 +112,7 @@ def get_file(fn, fp, tmppath):
def get_file_binary(fn, fp, tmppath):
path = join(tmppath, fp)
fpp = join(path, fn)
fs = open_fs(path)
fs = XRootDPyFS(path)
with fs.open(fn, "rb") as f:
fc = f.read()
return {"filename": fn, "dir": fp, "contents": fc, "full_path": fpp}
Expand All @@ -116,14 +121,14 @@ def get_file_binary(fn, fp, tmppath):
def copy_file(fn, fp, tmppath):
path = join(tmppath, fp)
fn_new = fn + "_copy"
this_fs = open_fs(path)
this_fs = XRootDPyFS(path)
this_fs.copy(fn, fn_new)
return fn_new


def get_copy_file(arg, binary=False):
# Would get called with e.g. arg=get_tsta_file(...)
fp = fs.path.dirname(arg["full_path"])
fp = dirname(arg["full_path"])
fn_new = copy_file(arg["filename"], "", fp)
return get_file_binary(fn_new, "", fp) if binary else get_file(fn_new, "", fp)

Expand Down Expand Up @@ -993,7 +998,7 @@ def test_readline(tmppath):
fb = get_copy_file(fd)
fp, fc = fd["full_path"], fd["contents"]

osfs = open_fs(fs.path.dirname(fd["full_path"]))
osfs = XRootDPyFS(dirname(fd["full_path"]))
xfile, pfile = XRootDPyFile(mkurl(fp), "r"), osfs.open(fb["filename"], "r")

assert xfile.readline() == pfile.readline().encode()
Expand Down Expand Up @@ -1104,7 +1109,7 @@ def test_readlines(tmppath):
fb = get_copy_file(fd)
fp, fc = fd["full_path"], fd["contents"]

osfs = open_fs(fs.path.dirname(fb["full_path"]))
osfs = XRootDPyFS(dirname(fb["full_path"]))
xfile, pfile = XRootDPyFile(mkurl(fp), "r"), osfs.open(fb["filename"], "r")

xfile.seek(0), pfile.seek(0)
Expand Down
13 changes: 1 addition & 12 deletions xrootdpyfs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,6 @@
>>> fs.listdir("xrootdpyfs")
['test.txt']

Or, alternatively using the PyFilesystem opener (note the first
``import xrootdpyfs`` is required to ensure the XRootDPyFS
opener is registered):

>>> import xrootdpyfs
>>> from fs.opener import open_fs
>>> fs = open_fs("root://localhost//tmp/")
>>> fs.listdir("xrootdpyfs")
['test.txt']

Reading files:

>>> f = fs.open("xrootdpyfs/test.txt")
Expand Down Expand Up @@ -183,9 +173,8 @@
"""

from .fs import XRootDPyFS
from .opener import XRootDPyOpener
from .xrdfile import XRootDPyFile

__version__ = "2.0.0"

__all__ = ("__version__", "XRootDPyFS", "XRootDPyOpener", "XRootDPyFile")
__all__ = ("__version__", "XRootDPyFS", "XRootDPyFile")
37 changes: 23 additions & 14 deletions xrootdpyfs/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,20 @@

import re
from glob import fnmatch
from urllib.parse import parse_qs, urlencode

from fs import ResourceType
from fs.base import FS
from fs.errors import (
from XRootD.client import CopyProcess, FileSystem
from XRootD.client.flags import (
AccessMode,
DirListFlags,
MkDirFlags,
QueryCode,
StatInfoFlags,
)

from .fs_utils.base import FS
from .fs_utils.enums import ResourceType
from .fs_utils.errors import (
DestinationExists,
DirectoryNotEmpty,
FSError,
Expand All @@ -34,18 +44,17 @@
ResourceNotFound,
Unsupported,
)
from fs.info import Info
from fs.path import basename, combine, dirname, frombase, isabs, join, normpath, relpath
from six.moves.urllib.parse import parse_qs, urlencode
from XRootD.client import CopyProcess, FileSystem
from XRootD.client.flags import (
AccessMode,
DirListFlags,
MkDirFlags,
QueryCode,
StatInfoFlags,
from .fs_utils.info import Info
from .fs_utils.path import (
basename,
combine,
dirname,
frombase,
isabs,
join,
normpath,
relpath,
)

from .utils import is_valid_path, is_valid_url, spliturl
from .xrdfile import XRootDPyFile

Expand Down
Empty file added xrootdpyfs/fs_utils/__init__.py
Empty file.
Loading
Loading