Skip to content

Commit 19edfad

Browse files
Add an optional xrootd extra and use it in CI (#117)
* Add optional xrootd extra * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix Ruff failure in package test * Restore xrootd server in CI * Require XRootD 6 in CI * Relax CI xrootd server requirement * Avoid pip xrootd in CI test jobs --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent d029576 commit 19edfad

10 files changed

Lines changed: 73 additions & 30 deletions

File tree

.github/CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ You can set up a development environment by running:
3232
```bash
3333
python3 -m venv .venv
3434
source ./.venv/bin/activate
35-
pip install -v -e .[dev]
35+
pip install -v -e .[dev,xrootd]
3636
```
3737

3838
If you have the
@@ -41,7 +41,7 @@ can instead do:
4141

4242
```bash
4343
py -m venv .venv
44-
py -m install -v -e .[dev]
44+
py -m install -v -e .[dev,xrootd]
4545
```
4646

4747
# Post setup

.github/workflows/ci.yml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,10 @@ jobs:
4848
python-version: ${{ matrix.python-version }}
4949
miniforge-version: latest
5050
activate-environment: fsspec
51-
- name: Install build environment
52-
run: |
53-
mamba install -c conda-forge "xrootd>=5.4.3"
51+
- name: Install XRootD server
52+
run: mamba install -c conda-forge xrootd
5453
- name: Install package
55-
run: python -m pip install .[test]
54+
run: python -m pip install ".[test]"
5655
- name: Test package
5756
run: |
5857
python -m pytest -vv tests --reruns 3 --reruns-delay 5 --only-rerun "(?i)OSError|FileNotFoundError|timeout|expired|connection|socket"
@@ -64,8 +63,8 @@ jobs:
6463
git clone https://github.com/scikit-hep/uproot5.git uproot
6564
git -C uproot checkout tags/v${UPROOT_VERSION}
6665
(cd uproot && python -m pip install . --group test)
67-
# Install xrootd-fsspec again because it may have been overwritten by uproot
68-
python -m pip install .[test]
66+
# Reinstall fsspec-xrootd after uproot without replacing the conda xrootd runtime.
67+
python -m pip install ".[test]"
6968
python -m pytest -vv -k "xrootd" uproot/tests --reruns 10 --reruns-delay 30 --only-rerun "(?i)OSError|FileNotFoundError|timeout|expired|connection|socket"
7069
7170
pass:

.github/workflows/docs.yml

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ jobs:
1010
docs:
1111
name: Build and deploy docs
1212
runs-on: ubuntu-latest
13-
defaults:
14-
run:
15-
shell: bash -l {0}
1613

1714
steps:
1815
- uses: actions/checkout@v6
@@ -23,17 +20,8 @@ jobs:
2320
with:
2421
python-version: "3.14"
2522

26-
- name: Set up Conda
27-
uses: conda-incubator/setup-miniconda@v3
28-
with:
29-
python-version: "3.14"
30-
miniforge-version: latest
31-
activate-environment: fsspec
32-
- name: Install build environment
33-
run: |
34-
mamba install -c conda-forge "xrootd>=5.4.3"
3523
- name: Install package
36-
run: python -m pip install -e .[docs]
24+
run: python -m pip install -e ".[docs,xrootd]"
3725

3826
- name: Build documentation
3927
run: |

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ An XRootD implementation for fsspec.
55
## Install
66

77
```bash
8-
pip install fsspec-xrootd
8+
pip install "fsspec-xrootd[xrootd]"
99
```
1010

1111
Supports Python 3.9 and newer.
1212

1313
## Purpose
1414

1515
To allow fsspec to use XRootD accessible storage systems. Install fsspec-xrootd
16-
alongside fsspec and have easy access to files stored on XRootD servers. Once
17-
installed, fsspec will be able to work with urls with the 'root' protocol. Only
18-
tested with Linux at this time.
16+
with the optional `xrootd` extra alongside fsspec and have easy access to files
17+
stored on XRootD servers. Once installed, fsspec will be able to work with urls
18+
with the 'root' protocol. Only tested with Linux at this time.
1919

2020
## Documentation
2121

docs/index.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ Install
99

1010
.. code:: bash
1111
12-
pip install fsspec-xrootd
12+
pip install "fsspec-xrootd[xrootd]"
1313
1414
Purpose
1515
-------
1616

17-
To allow fsspec to use XRootD accessible storage systems. Install fsspec-xrootd alongside fsspec and have easy access to files stored on XRootD serevrs. Once installed, fsspec will be able to work with urls with the 'root' protocol. Only tested with Linux at this time.
17+
To allow fsspec to use XRootD accessible storage systems. Install
18+
``fsspec-xrootd[xrootd]`` alongside fsspec and have easy access to files stored
19+
on XRootD servers. Once installed, fsspec will be able to work with urls with
20+
the ``root`` protocol. Only tested with Linux at this time.
1821

1922
.. toctree::
2023
:maxdepth: 3

noxfile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def tests(session: nox.Session) -> None:
2424
"""
2525
Run the unit and regular tests.
2626
"""
27-
session.install(".[test]")
27+
session.install(".[test,xrootd]")
2828
session.run("pytest", *session.posargs)
2929

3030

@@ -34,7 +34,7 @@ def docs(session: nox.Session) -> None:
3434
Build the docs. Pass "serve" to serve.
3535
"""
3636

37-
session.install(".[docs]")
37+
session.install(".[docs,xrootd]")
3838
session.chdir("docs")
3939
session.run("sphinx-build", "-M", "html", ".", "_build")
4040

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ docs = [
5050
"sphinx-copybutton",
5151
]
5252
test = ["pytest>=6", "pytest-rerunfailures", "pytest-timeout"]
53+
xrootd = ["xrootd>=6.0.0"]
5354

5455
[tool.setuptools]
5556
include-package-data = true

src/fsspec_xrootd/__init__.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,32 @@
77

88
from __future__ import annotations
99

10+
from typing import TYPE_CHECKING, Any
11+
1012
from ._version import version as __version__
11-
from .xrootd import XRootDFile, XRootDFileSystem
13+
14+
if TYPE_CHECKING:
15+
from .xrootd import XRootDFile, XRootDFileSystem
1216

1317
__all__ = ("__version__", "XRootDFileSystem", "XRootDFile")
18+
19+
20+
def __getattr__(name: str) -> Any:
21+
if name not in {"XRootDFile", "XRootDFileSystem"}:
22+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
23+
24+
try:
25+
from .xrootd import XRootDFile, XRootDFileSystem
26+
except ModuleNotFoundError as exc:
27+
if exc.name == "XRootD":
28+
raise ModuleNotFoundError(
29+
"The 'xrootd' package is required to use fsspec-xrootd. "
30+
'Install it with `pip install "fsspec-xrootd[xrootd]"`.'
31+
) from exc
32+
raise
33+
34+
globals().update({
35+
"XRootDFile": XRootDFile,
36+
"XRootDFileSystem": XRootDFileSystem,
37+
})
38+
return globals()[name]

tests/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ def localserver(tmpdir_factory):
3535
fout.write("all.export /Folder\n")
3636
fout.write(f"oss.localroot {srvdir}\n")
3737
xrdexe = shutil.which("xrootd")
38+
if xrdexe is None:
39+
pytest.skip("xrootd executable is required for basic I/O integration tests")
3840
proc = subprocess.Popen([xrdexe, "-p", str(XROOTD_PORT), "-c", cfgfile])
3941
time.sleep(2) # give it some startup
4042
yield "root://localhost//Folder", tempPath

tests/test_package.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,32 @@
11
from __future__ import annotations
22

3+
import builtins
4+
import importlib
5+
import sys
6+
7+
import pytest
8+
39
import fsspec_xrootd as m
410

511

612
def test_version():
713
assert m.__version__
14+
15+
16+
def test_import_without_xrootd(monkeypatch):
17+
original_import = builtins.__import__
18+
19+
def raising_import(name, *args, **kwargs):
20+
if name == "XRootD":
21+
raise ModuleNotFoundError("No module named 'XRootD'", name="XRootD")
22+
return original_import(name, *args, **kwargs)
23+
24+
monkeypatch.setattr(builtins, "__import__", raising_import)
25+
for module_name in ("fsspec_xrootd", "fsspec_xrootd.xrootd", "XRootD"):
26+
sys.modules.pop(module_name, None)
27+
28+
module = importlib.import_module("fsspec_xrootd")
29+
30+
assert module.__version__
31+
with pytest.raises(ModuleNotFoundError, match="Install it with"):
32+
_ = module.XRootDFileSystem

0 commit comments

Comments
 (0)