From 7a3a6dcada65fac32e817f266426429bc2fd9ee0 Mon Sep 17 00:00:00 2001 From: Mike Taves Date: Wed, 20 Oct 2021 23:35:16 +1300 Subject: [PATCH 1/2] Check for path-like objects rather than Path type, use os.fspath --- xarray/backends/api.py | 19 +++++++++---------- xarray/backends/common.py | 7 +++---- xarray/backends/netCDF4_.py | 3 +-- xarray/backends/zarr.py | 3 +-- xarray/core/dataset.py | 12 ++++++------ xarray/tutorial.py | 2 +- 6 files changed, 21 insertions(+), 25 deletions(-) diff --git a/xarray/backends/api.py b/xarray/backends/api.py index 6d73946bb59..7884353b7a0 100644 --- a/xarray/backends/api.py +++ b/xarray/backends/api.py @@ -2,7 +2,6 @@ from glob import glob from io import BytesIO from numbers import Number -from pathlib import Path from typing import ( TYPE_CHECKING, Callable, @@ -808,7 +807,7 @@ def open_mfdataset( - "override": if indexes are of same size, rewrite indexes to be those of the first object with that dimension. Indexes for the same dimension must have the same size in all objects. - attrs_file : str or pathlib.Path, optional + attrs_file : str or path-like, optional Path of the file used to read global attributes from. By default global attributes are read from the first file provided, with wildcard matches sorted by filename. @@ -866,7 +865,7 @@ def open_mfdataset( else: paths = sorted(glob(_normalize_path(paths))) else: - paths = [str(p) if isinstance(p, Path) else p for p in paths] + paths = [os.fspath(p) if isinstance(p, os.PathLike) else p for p in paths] if not paths: raise OSError("no files to open") @@ -958,8 +957,8 @@ def multi_file_closer(): # read global attributes from the attrs_file or from the first dataset if attrs_file is not None: - if isinstance(attrs_file, Path): - attrs_file = str(attrs_file) + if isinstance(attrs_file, os.PathLike): + attrs_file = os.fspath(attrs_file) combined.attrs = datasets[paths.index(attrs_file)].attrs return combined @@ -992,8 +991,8 @@ def to_netcdf( The ``multifile`` argument is only for the private use of save_mfdataset. """ - if isinstance(path_or_file, Path): - path_or_file = str(path_or_file) + if isinstance(path_or_file, os.PathLike): + path_or_file = os.fspath(path_or_file) if encoding is None: encoding = {} @@ -1134,7 +1133,7 @@ def save_mfdataset( ---------- datasets : list of Dataset List of datasets to save. - paths : list of str or list of Path + paths : list of str or list of path-like objects List of paths to which to save each corresponding dataset. mode : {"w", "a"}, optional Write ("w") or append ("a") mode. If mode="w", any existing file at @@ -1302,7 +1301,7 @@ def check_dtype(var): def to_zarr( dataset: Dataset, - store: Union[MutableMapping, str, Path] = None, + store: Union[MutableMapping, str, os.PathLike] = None, chunk_store=None, mode: str = None, synchronizer=None, @@ -1326,7 +1325,7 @@ def to_zarr( if v.size == 0: v.load() - # expand str and Path arguments + # expand str and path-like arguments store = _normalize_path(store) chunk_store = _normalize_path(chunk_store) diff --git a/xarray/backends/common.py b/xarray/backends/common.py index 64a245ddead..f33a9ab2814 100644 --- a/xarray/backends/common.py +++ b/xarray/backends/common.py @@ -1,8 +1,7 @@ import logging -import os.path +import os import time import traceback -from pathlib import Path from typing import Any, Dict, Tuple, Type, Union import numpy as np @@ -20,8 +19,8 @@ def _normalize_path(path): - if isinstance(path, Path): - path = str(path) + if isinstance(path, os.PathLike): + path = os.fspath(path) if isinstance(path, str) and not is_remote_uri(path): path = os.path.abspath(os.path.expanduser(path)) diff --git a/xarray/backends/netCDF4_.py b/xarray/backends/netCDF4_.py index 769c96c99ce..4536f74766c 100644 --- a/xarray/backends/netCDF4_.py +++ b/xarray/backends/netCDF4_.py @@ -1,7 +1,6 @@ import functools import operator import os -import pathlib from contextlib import suppress import numpy as np @@ -346,7 +345,7 @@ def open( autoclose=False, ): - if isinstance(filename, pathlib.Path): + if isinstance(filename, os.PathLike): filename = os.fspath(filename) if not isinstance(filename, str): diff --git a/xarray/backends/zarr.py b/xarray/backends/zarr.py index 12499103fb9..d8548ca702f 100644 --- a/xarray/backends/zarr.py +++ b/xarray/backends/zarr.py @@ -1,5 +1,4 @@ import os -import pathlib import warnings from distutils.version import LooseVersion @@ -346,7 +345,7 @@ def open_group( ): # zarr doesn't support pathlib.Path objects yet. zarr-python#601 - if isinstance(store, pathlib.Path): + if isinstance(store, os.PathLike): store = os.fspath(store) open_kwargs = dict( diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 4b1b1de222d..86b4549ff3f 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -7,7 +7,7 @@ from html import escape from numbers import Number from operator import methodcaller -from pathlib import Path +from os import PathLike from typing import ( TYPE_CHECKING, Any, @@ -1827,7 +1827,7 @@ def to_netcdf( Parameters ---------- - path : str, Path or file-like, optional + path : str, path-like or file-like, optional Path to which to save this dataset. File-like objects are only supported by the scipy engine. If no path is provided, this function returns the resulting netCDF file as bytes; in this case, @@ -1909,8 +1909,8 @@ def to_netcdf( def to_zarr( self, - store: Union[MutableMapping, str, Path] = None, - chunk_store: Union[MutableMapping, str, Path] = None, + store: Union[MutableMapping, str, PathLike] = None, + chunk_store: Union[MutableMapping, str, PathLike] = None, mode: str = None, synchronizer=None, group: str = None, @@ -1939,9 +1939,9 @@ def to_zarr( Parameters ---------- - store : MutableMapping, str or Path, optional + store : MutableMapping, str or path-like, optional Store or path to directory in local or remote file system. - chunk_store : MutableMapping, str or Path, optional + chunk_store : MutableMapping, str or path-like, optional Store or path to directory in local or remote file system only for Zarr array chunks. Requires zarr-python v2.4.0 or later. mode : {"w", "w-", "a", "r+", None}, optional diff --git a/xarray/tutorial.py b/xarray/tutorial.py index 78471be7a0e..b0a3e110d84 100644 --- a/xarray/tutorial.py +++ b/xarray/tutorial.py @@ -23,7 +23,7 @@ def _construct_cache_dir(path): import pooch - if isinstance(path, pathlib.Path): + if isinstance(path, os.PathLike): path = os.fspath(path) elif path is None: path = pooch.os_cache(_default_cache_dir_name) From 6c7d60e78fdaf473ed5ae45e9aaf5b90dfeffe5f Mon Sep 17 00:00:00 2001 From: Mike Taves Date: Mon, 25 Oct 2021 22:43:02 +1300 Subject: [PATCH 2/2] Add whats-new entry --- doc/whats-new.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 1ade92f8588..339904b7f88 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -80,6 +80,9 @@ Bug fixes By `Jimmy Westling `_. - Numbers are properly formatted in a plot's title (:issue:`5788`, :pull:`5789`). By `Maxime Liquet `_. +- With backends, check for path-like objects rather than ``pathlib.Path`` + type, use ``os.fspath`` (:pull:`5879`). + By `Mike Taves `_. Documentation ~~~~~~~~~~~~~