Skip to content

Commit 59b6496

Browse files
authored
feat: set fsspec as default source (#1023)
* feat: add fsspec as required dependency (#1021) * fsspec requirements * simplify fsspec import * use loop property * correctly create schemes list * remove deprecated handlers from docs * simplify source selection * return object source * pickle executor * rename test * test more handlers * option to check writeable file-like object * rename test * explicitly set handler * fix s3 source * rename test * Revert "fix s3 source" This reverts commit e76fdbb. * sesparate PR for s3 fix (#1024) * strip file:// * rename test * rename tests * add aiohttp skip * attempt to parse windows paths * test ci * Revert "test ci" This reverts commit 4c1c8a5. * rename test * remove fsspec from test * remove *_handler options * update defaults * do not override default s3 * do not use fsspec for multiprocessing * rename test * fix not selecting object source * missing import * normalize doc * remove helper * never return None as source * remove unnecessary xrootd source default override since fsspec is default now * rename test * add empty class to pass old pickle test
1 parent 472be82 commit 59b6496

18 files changed

+85
-232
lines changed

src/uproot/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@
7272
isort:skip_file
7373
"""
7474

75-
7675
from uproot.version import __version__
7776
import uproot.const
7877
import uproot.extras
@@ -92,6 +91,7 @@
9291
from uproot.source.xrootd import MultithreadedXRootDSource
9392
from uproot.source.s3 import S3Source
9493
from uproot.source.object import ObjectSource
94+
from uproot.source.fsspec import FSSpecSource
9595
from uproot.source.cursor import Cursor
9696
from uproot.source.futures import TrivialExecutor
9797
from uproot.source.futures import ThreadPoolExecutor

src/uproot/_dask.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,6 @@ def dask(
134134
Options (type; default):
135135
136136
* handler (:doc:`uproot.source.chunk.Source` class; None)
137-
* file_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
138-
* xrootd_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
139-
* s3_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
140-
* http_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
141-
* object_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
142137
* timeout (float for HTTP, int for XRootD; 30)
143138
* max_num_elements (None or int; None)
144139
* num_workers (int; 1)

src/uproot/_util.py

Lines changed: 24 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -354,63 +354,30 @@ def file_path_to_source_class(file_path, options):
354354
Use a file path to get the :doc:`uproot.source.chunk.Source` class that would read it.
355355
356356
Returns a tuple of (class, file_path) where the class is a subclass of :doc:`uproot.source.chunk.Source`.
357-
358-
The "handler" option is the preferred way to specify a custom source class.
359-
The "*_handler" options are for backwards compatibility and will override the "handler" option if set.
360357
"""
358+
361359
import uproot.source.chunk
362360

363361
file_path = regularize_path(file_path)
364362

365-
out = options["handler"]
366-
if out is not None:
367-
if not (isinstance(out, type) and issubclass(out, uproot.source.chunk.Source)):
368-
raise TypeError(
369-
f"'handler' is not a class object inheriting from Source: {out!r}"
370-
)
371-
# check if "object_handler" is set
372-
if (
373-
options["object_handler"] is not None
374-
or options["file_handler"] is not None
375-
or options["xrootd_handler"] is not None
376-
or options["s3_handler"] is not None
377-
or options["http_handler"] is not None
363+
source_cls = options["handler"]
364+
if source_cls is not None:
365+
if not (
366+
isinstance(source_cls, type)
367+
and issubclass(source_cls, uproot.source.chunk.Source)
378368
):
379-
# These options will override the "handler" option for backwards compatibility
380-
warnings.warn(
381-
"""In version 5.2.0, the '*_handler' argument ('http_handler`, 's3_handler', etc.) will be removed from 'uproot.open'. Use 'handler' instead.""",
382-
stacklevel=1,
369+
raise TypeError(
370+
f"'handler' is not a class object inheriting from Source: {source_cls!r}"
383371
)
384-
else:
385-
return out, file_path
372+
return source_cls, file_path
386373

387374
if (
388375
not isinstance(file_path, str)
389376
and hasattr(file_path, "read")
390377
and hasattr(file_path, "seek")
391378
):
392-
out = options["object_handler"]
393-
if out is None:
394-
out = uproot.source.object.ObjectSource
395-
else:
396-
warnings.warn(
397-
f"""In version 5.2.0, the 'object_handler' argument will be removed from 'uproot.open'. Use
398-
uproot.open(..., handler={out!r})
399-
instead.
400-
401-
To raise these warnings as errors (and get stack traces to find out where they're called), run
402-
import warnings
403-
warnings.filterwarnings("error", module="uproot.*")
404-
after the first `import uproot` or use `@pytest.mark.filterwarnings("error:::uproot.*")` in pytest.""",
405-
DeprecationWarning,
406-
stacklevel=1,
407-
)
408-
if not (isinstance(out, type) and issubclass(out, uproot.source.chunk.Source)):
409-
raise TypeError(
410-
f"'object_handler' is not a class object inheriting from Source: {out!r}"
411-
)
412-
413-
return out, file_path
379+
source_cls = uproot.source.object.ObjectSource
380+
return source_cls, file_path
414381

415382
windows_absolute_path = None
416383
if win and _windows_absolute_path_pattern.match(file_path) is not None:
@@ -442,107 +409,27 @@ def file_path_to_source_class(file_path, options):
442409
else:
443410
file_path = windows_absolute_path
444411

445-
out = options["file_handler"]
446-
if out is None:
447-
out = uproot.source.file.MemmapSource
448-
else:
449-
warnings.warn(
450-
f"""In version 5.2.0, the 'file_handler' argument will be removed from 'uproot.open'. Use
451-
uproot.open(..., handler={out!r}
452-
instead.
453-
454-
To raise these warnings as errors (and get stack traces to find out where they're called), run
455-
import warnings
456-
warnings.filterwarnings("error", module="uproot.*")
457-
after the first `import uproot` or use `@pytest.mark.filterwarnings("error:::uproot.*")` in pytest.""",
458-
DeprecationWarning,
459-
stacklevel=1,
460-
)
412+
# uproot.source.file.MemmapSource
413+
source_cls = uproot.source.fsspec.FSSpecSource
461414

462-
if not (isinstance(out, type) and issubclass(out, uproot.source.chunk.Source)):
463-
raise TypeError(
464-
"'file_handler' is not a class object inheriting from Source: "
465-
+ repr(out)
466-
)
467-
return out, os.path.expanduser(file_path)
415+
return source_cls, os.path.expanduser(file_path)
468416

469417
elif scheme == "root":
470-
out = options["xrootd_handler"]
471-
if out is None:
472-
out = uproot.source.xrootd.XRootDSource
473-
else:
474-
warnings.warn(
475-
f"""In version 5.2.0, the 'xrootd_handler' argument will be removed from 'uproot.open'. Use
476-
uproot.open(..., handler={out!r}
477-
instead.
478-
479-
To raise these warnings as errors (and get stack traces to find out where they're called), run
480-
import warnings
481-
warnings.filterwarnings("error", module="uproot.*")
482-
after the first `import uproot` or use `@pytest.mark.filterwarnings("error:::uproot.*")` in pytest.""",
483-
DeprecationWarning,
484-
stacklevel=1,
485-
)
486-
if not (isinstance(out, type) and issubclass(out, uproot.source.chunk.Source)):
487-
raise TypeError(
488-
"'xrootd_handler' is not a class object inheriting from Source: "
489-
+ repr(out)
490-
)
491-
return out, file_path
418+
# uproot.source.xrootd.XRootDSource
419+
source_cls = uproot.source.fsspec.FSSpecSource
420+
return source_cls, file_path
492421

493422
elif scheme == "s3":
494-
out = options["s3_handler"]
495-
if out is None:
496-
out = uproot.source.s3.S3Source
497-
else:
498-
warnings.warn(
499-
f"""In version 5.2.0, the 's3_handler' argument will be removed from 'uproot.open'. Use
500-
uproot.open(..., handler={out!r}
501-
instead.
502-
503-
To raise these warnings as errors (and get stack traces to find out where they're called), run
504-
import warnings
505-
warnings.filterwarnings("error", module="uproot.*")
506-
after the first `import uproot` or use `@pytest.mark.filterwarnings("error:::uproot.*")` in pytest.""",
507-
DeprecationWarning,
508-
stacklevel=1,
509-
)
510-
if not (isinstance(out, type) and issubclass(out, uproot.source.chunk.Source)):
511-
raise TypeError(
512-
"'s3' is not a class object inheriting from Source: " + repr(out)
513-
)
514-
return out, file_path
423+
# https://github.com/scikit-hep/uproot5/pull/1012
424+
source_cls = uproot.source.s3.S3Source
425+
return source_cls, file_path
515426

516427
elif scheme in ("http", "https"):
517-
out = options["http_handler"]
518-
if out is None:
519-
out = uproot.source.http.HTTPSource
520-
else:
521-
warnings.warn(
522-
f"""In version 5.2.0, the 'http_handler' argument will be removed from 'uproot.open'. Use
523-
uproot.open(..., handler={out!r}
524-
instead.
525-
526-
To raise these warnings as errors (and get stack traces to find out where they're called), run
527-
import warnings
528-
warnings.filterwarnings("error", module="uproot.*")
529-
after the first `import uproot` or use `@pytest.mark.filterwarnings("error:::uproot.*")` in pytest.""",
530-
DeprecationWarning,
531-
stacklevel=1,
532-
)
533-
if not (isinstance(out, type) and issubclass(out, uproot.source.chunk.Source)):
534-
raise TypeError(
535-
"'http_handler' is not a class object inheriting from Source: "
536-
+ repr(out)
537-
)
538-
return out, file_path
539-
540-
else:
541-
# try to use fsspec before raising an error
542-
if scheme in _schemes:
543-
return uproot.source.fsspec.FSSpecSource, file_path
428+
# uproot.source.http.HTTPSource
429+
source_cls = uproot.source.fsspec.FSSpecSource
430+
return source_cls, file_path
544431

545-
raise ValueError(f"URI scheme not recognized: {file_path}")
432+
return uproot.source.fsspec.FSSpecSource, file_path
546433

547434

548435
if isinstance(__builtins__, dict):

src/uproot/behaviors/TBranch.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,6 @@ def iterate(
153153
Options (type; default):
154154
155155
* handler (:doc:`uproot.source.chunk.Source` class; None)
156-
* file_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
157-
* xrootd_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
158-
* s3_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
159-
* http_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
160-
* object_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
161156
* timeout (float for HTTP, int for XRootD; 30)
162157
* max_num_elements (None or int; None)
163158
* num_workers (int; 1)
@@ -327,11 +322,6 @@ def concatenate(
327322
Options (type; default):
328323
329324
* handler (:doc:`uproot.source.chunk.Source` class; None)
330-
* file_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
331-
* xrootd_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
332-
* s3_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
333-
* http_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
334-
* object_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
335325
* timeout (float for HTTP, int for XRootD; 30)
336326
* max_num_elements (None or int; None)
337327
* num_workers (int; 1)

src/uproot/reading.py

Lines changed: 20 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
import struct
1212
import sys
1313
import uuid
14-
import warnings
1514
from collections.abc import Mapping, MutableMapping
1615

1716
import uproot
1817
import uproot.behaviors.TBranch
18+
import uproot.source.fsspec
1919
from uproot._util import no_filter
2020

2121

@@ -42,7 +42,7 @@ def open(
4242
``"rel/file.root:tdirectory/ttree"``, ``Path("rel:/file.root")``,
4343
``Path("/abs/path:stuff.root")``
4444
object_cache (None, MutableMapping, or int): Cache of objects drawn
45-
from ROOT directories (e.g histograms, TTrees, other directories);
45+
from ROOT directories (e.g. histograms, TTrees, other directories);
4646
if None, do not use a cache; if an int, create a new cache of this
4747
size.
4848
array_cache (None, MutableMapping, or memory size): Cache of arrays
@@ -77,11 +77,6 @@ def open(
7777
Options (type; default):
7878
7979
* handler (:doc:`uproot.source.chunk.Source` class; None)
80-
* file_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
81-
* xrootd_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
82-
* s3_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
83-
* http_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
84-
* object_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
8580
* timeout (float for HTTP, int for XRootD; 30)
8681
* max_num_elements (None or int; None)
8782
* num_workers (int; 1)
@@ -156,43 +151,22 @@ def open(
156151
return file.root_directory[object_path]
157152

158153

154+
open.defaults = {
155+
"handler": None,
156+
"timeout": 30,
157+
"max_num_elements": None,
158+
"num_workers": 1,
159+
"use_threads": sys.platform != "emscripten",
160+
"num_fallback_workers": 10,
161+
"begin_chunk_size": 403, # the smallest a ROOT file can be
162+
"minimal_ttree_metadata": True,
163+
}
164+
165+
159166
class _OpenDefaults(dict):
160-
def __getitem__(self, where):
161-
if where == "xrootd_handler" and where not in self:
162-
# See https://github.com/scikit-hep/uproot5/issues/294
163-
if uproot.extras.older_xrootd("5.2.0"):
164-
message = (
165-
f"XRootD {uproot.extras.xrootd_version()} is not fully supported; "
166-
"""either upgrade to 5.2.0+ or set
167-
168-
open.defaults["xrootd_handler"] = uproot.MultithreadedXRootDSource
169-
"""
170-
)
171-
warnings.warn(message, FutureWarning, stacklevel=1)
172-
173-
# The key should still be set, regardless of whether we see the warning.
174-
self["xrootd_handler"] = uproot.source.xrootd.XRootDSource
175-
176-
return dict.__getitem__(self, where)
177-
178-
179-
open.defaults = _OpenDefaults(
180-
{
181-
"handler": None, # To be updated to fsspec source
182-
"file_handler": None, # Deprecated
183-
"s3_handler": None, # Deprecated
184-
"http_handler": None, # Deprecated
185-
"object_handler": None, # Deprecated
186-
"xrootd_handler": None, # Deprecated
187-
"timeout": 30,
188-
"max_num_elements": None,
189-
"num_workers": 1,
190-
"use_threads": sys.platform != "emscripten",
191-
"num_fallback_workers": 10,
192-
"begin_chunk_size": 403, # the smallest a ROOT file can be
193-
"minimal_ttree_metadata": True,
194-
}
195-
)
167+
def __init__(self):
168+
raise NotImplementedError # kept for backwards compatibility
169+
196170

197171
must_be_attached = [
198172
"TROOT",
@@ -536,11 +510,6 @@ class ReadOnlyFile(CommonFileMethods):
536510
Options (type; default):
537511
538512
* handler (:doc:`uproot.source.chunk.Source` class; None)
539-
* file_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
540-
* xrootd_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
541-
* s3_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
542-
* http_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
543-
* object_handler (:doc:`uproot.source.chunk.Source` class; None) (Deprecated: Use `handler` instead. If set, this will take precedence over `handler`)
544513
* timeout (float for HTTP, int for XRootD; 30)
545514
* max_num_elements (None or int; None)
546515
* num_workers (int; 1)
@@ -571,7 +540,7 @@ def __init__(
571540
self.decompression_executor = decompression_executor
572541
self.interpretation_executor = interpretation_executor
573542

574-
self._options = _OpenDefaults(open.defaults)
543+
self._options = open.defaults.copy()
575544
self._options.update(options)
576545
for option in ["begin_chunk_size"]:
577546
self._options[option] = uproot._util.memory_size(self._options[option])
@@ -581,10 +550,10 @@ def __init__(
581550

582551
self.hook_before_create_source()
583552

584-
Source, file_path = uproot._util.file_path_to_source_class(
553+
source_cls, file_path = uproot._util.file_path_to_source_class(
585554
file_path, self._options
586555
)
587-
self._source = Source(file_path, **self._options)
556+
self._source = source_cls(file_path, **self._options)
588557

589558
self.hook_before_get_chunks()
590559

src/uproot/source/fsspec.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def __init__(self, file_path: str, **options):
3232
exclude_keys = set(default_options.keys())
3333
storage_options = {k: v for k, v in options.items() if k not in exclude_keys}
3434

35-
self._executor = FSSpecLoopExecutor()
35+
self._open()
3636

3737
self._fs, self._file_path = fsspec.core.url_to_fs(file_path, **storage_options)
3838

@@ -46,6 +46,9 @@ def __init__(self, file_path: str, **options):
4646
self._num_requested_bytes = 0
4747
self.__enter__()
4848

49+
def _open(self):
50+
self._executor = FSSpecLoopExecutor()
51+
4952
def __repr__(self):
5053
path = repr(self._file_path)
5154
if len(self._file_path) > 10:
File renamed without changes.

0 commit comments

Comments
 (0)