fpathlib 0.1.2.post0__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. fpathlib-0.1.3/.gitignore +7 -0
  2. fpathlib-0.1.3/MANIFEST.in +1 -0
  3. fpathlib-0.1.3/PKG-INFO +78 -0
  4. fpathlib-0.1.3/README.md +61 -0
  5. fpathlib-0.1.3/TODO.txt +7 -0
  6. fpathlib-0.1.3/docs/source/api.rst +36 -0
  7. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/docs/source/conf.py +4 -0
  8. fpathlib-0.1.3/docs/source/index.rst +66 -0
  9. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/pyproject.toml +4 -3
  10. fpathlib-0.1.3/scripts/deploy.sh +3 -0
  11. fpathlib-0.1.3/scripts/docs.sh +3 -0
  12. fpathlib-0.1.3/scripts/pypi.sh +20 -0
  13. fpathlib-0.1.3/scripts/tag.sh +33 -0
  14. fpathlib-0.1.3/src/fpathlib/__init__.py +16 -0
  15. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/src/fpathlib/_version.py +3 -3
  16. fpathlib-0.1.3/src/fpathlib/expand.py +106 -0
  17. fpathlib-0.1.3/src/fpathlib/ext/polars.py +325 -0
  18. fpathlib-0.1.3/src/fpathlib/fpath.py +160 -0
  19. fpathlib-0.1.3/src/fpathlib/path.py +86 -0
  20. fpathlib-0.1.3/src/fpathlib/utils.py +22 -0
  21. fpathlib-0.1.3/src/fpathlib.egg-info/PKG-INFO +78 -0
  22. fpathlib-0.1.3/src/fpathlib.egg-info/SOURCES.txt +30 -0
  23. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/src/fpathlib.egg-info/requires.txt +2 -0
  24. fpathlib-0.1.3/src/fpathlib.egg-info/scm_file_list.json +32 -0
  25. fpathlib-0.1.3/src/fpathlib.egg-info/scm_version.json +8 -0
  26. fpathlib-0.1.2.post0/PKG-INFO +0 -19
  27. fpathlib-0.1.2.post0/README.md +0 -4
  28. fpathlib-0.1.2.post0/docs/build/doctrees/environment.pickle +0 -0
  29. fpathlib-0.1.2.post0/docs/build/doctrees/index.doctree +0 -0
  30. fpathlib-0.1.2.post0/docs/build/html/.buildinfo +0 -4
  31. fpathlib-0.1.2.post0/docs/build/html/.buildinfo.bak +0 -4
  32. fpathlib-0.1.2.post0/docs/build/html/_sources/index.rst.txt +0 -17
  33. fpathlib-0.1.2.post0/docs/build/html/_static/base-stemmer.js +0 -476
  34. fpathlib-0.1.2.post0/docs/build/html/_static/basic.css +0 -906
  35. fpathlib-0.1.2.post0/docs/build/html/_static/debug.css +0 -69
  36. fpathlib-0.1.2.post0/docs/build/html/_static/doctools.js +0 -150
  37. fpathlib-0.1.2.post0/docs/build/html/_static/documentation_options.js +0 -13
  38. fpathlib-0.1.2.post0/docs/build/html/_static/english-stemmer.js +0 -1066
  39. fpathlib-0.1.2.post0/docs/build/html/_static/file.png +0 -0
  40. fpathlib-0.1.2.post0/docs/build/html/_static/language_data.js +0 -13
  41. fpathlib-0.1.2.post0/docs/build/html/_static/minus.png +0 -0
  42. fpathlib-0.1.2.post0/docs/build/html/_static/plus.png +0 -0
  43. fpathlib-0.1.2.post0/docs/build/html/_static/pygments.css +0 -250
  44. fpathlib-0.1.2.post0/docs/build/html/_static/scripts/furo.js +0 -3
  45. fpathlib-0.1.2.post0/docs/build/html/_static/scripts/furo.js.LICENSE.txt +0 -7
  46. fpathlib-0.1.2.post0/docs/build/html/_static/scripts/furo.js.map +0 -1
  47. fpathlib-0.1.2.post0/docs/build/html/_static/searchtools.js +0 -693
  48. fpathlib-0.1.2.post0/docs/build/html/_static/skeleton.css +0 -296
  49. fpathlib-0.1.2.post0/docs/build/html/_static/sphinx_highlight.js +0 -159
  50. fpathlib-0.1.2.post0/docs/build/html/_static/styles/furo-extensions.css +0 -2
  51. fpathlib-0.1.2.post0/docs/build/html/_static/styles/furo-extensions.css.map +0 -1
  52. fpathlib-0.1.2.post0/docs/build/html/_static/styles/furo.css +0 -2
  53. fpathlib-0.1.2.post0/docs/build/html/_static/styles/furo.css.map +0 -1
  54. fpathlib-0.1.2.post0/docs/build/html/genindex.html +0 -264
  55. fpathlib-0.1.2.post0/docs/build/html/index.html +0 -275
  56. fpathlib-0.1.2.post0/docs/build/html/objects.inv +0 -0
  57. fpathlib-0.1.2.post0/docs/build/html/search.html +0 -275
  58. fpathlib-0.1.2.post0/docs/build/html/searchindex.js +0 -1
  59. fpathlib-0.1.2.post0/docs/source/index.rst +0 -17
  60. fpathlib-0.1.2.post0/scripts/pypi.sh +0 -4
  61. fpathlib-0.1.2.post0/scripts/tag.sh +0 -7
  62. fpathlib-0.1.2.post0/src/fpathlib/__init__.py +0 -9
  63. fpathlib-0.1.2.post0/src/fpathlib/__pycache__/__init__.cpython-313.pyc +0 -0
  64. fpathlib-0.1.2.post0/src/fpathlib/__pycache__/path.cpython-313.pyc +0 -0
  65. fpathlib-0.1.2.post0/src/fpathlib/path.py +0 -121
  66. fpathlib-0.1.2.post0/src/fpathlib.egg-info/PKG-INFO +0 -19
  67. fpathlib-0.1.2.post0/src/fpathlib.egg-info/SOURCES.txt +0 -51
  68. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/LICENSE +0 -0
  69. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/docs/Makefile +0 -0
  70. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/docs/make.bat +0 -0
  71. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/setup.cfg +0 -0
  72. /fpathlib-0.1.2.post0/docs/build/html/_static/scripts/furo-extensions.js → /fpathlib-0.1.3/src/fpathlib/ext/__init__.py +0 -0
  73. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/src/fpathlib.egg-info/dependency_links.txt +0 -0
  74. {fpathlib-0.1.2.post0 → fpathlib-0.1.3}/src/fpathlib.egg-info/top_level.txt +0 -0
@@ -0,0 +1,7 @@
1
+ __pycache__
2
+ src/fpathlib.egg-info
3
+ docs/build
4
+ .pytest_cache
5
+ dist
6
+ build
7
+ src/fpathlib/_version.py
@@ -0,0 +1 @@
1
+ prune tests
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.4
2
+ Name: fpathlib
3
+ Version: 0.1.3
4
+ Summary: A package to combine paths with metadata
5
+ Author-email: "C. Lockhart" <clockha2@gmu.edu>
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: parse
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest; extra == "dev"
12
+ Requires-Dist: black; extra == "dev"
13
+ Requires-Dist: sphinx; extra == "dev"
14
+ Requires-Dist: furo; extra == "dev"
15
+ Requires-Dist: polars; extra == "dev"
16
+ Dynamic: license-file
17
+
18
+ fpathlib
19
+ ========
20
+
21
+ A Python package for adding metadata to file paths.
22
+
23
+ `fpathlib` combines file paths with the metadata encoded in their names. It
24
+ does this with an f-string-like path pattern -- `FPath` -- whose
25
+ `{variable}` fields are captured out of every matching path on disk.
26
+
27
+ ```python
28
+ from fpathlib import expand_fpath
29
+
30
+ # Given files like data/tr1/output/0/job2.log, data/tr2/output/1/job0.log, ...
31
+ expanded = expand_fpath("data/tr{trajectory:d}/output/{replica:d}/job{job:d}.log")
32
+
33
+ for path in expanded:
34
+ print(path, path.metadata)
35
+ # data/tr1/output/0/job2.log {'trajectory': 1, 'replica': 0, 'job': 2}
36
+ # data/tr2/output/1/job0.log {'trajectory': 2, 'replica': 1, 'job': 0}
37
+ ```
38
+
39
+ Combine the metadata for every matched path into a single table:
40
+
41
+ ```python
42
+ df = expanded.to_polars()
43
+ ```
44
+
45
+ `fpathlib.ext.polars` goes a step further: it wraps `polars`'s own
46
+ `read_csv`/`scan_csv`/`read_txt`/`scan_txt` so that an expandable path
47
+ pattern is accepted directly, and the resulting DataFrame or LazyFrame comes
48
+ back with the metadata already joined in.
49
+
50
+ ```python
51
+ import fpathlib.ext.polars as pl
52
+
53
+ df = pl.read_csv(
54
+ "data/tr{trajectory:d}/output/{replica:d}/job{job:d}.log",
55
+ has_header=False,
56
+ )
57
+ # df has columns "column_1", ..., plus "trajectory", "replica", "job"
58
+ ```
59
+
60
+ Installation
61
+ ------------
62
+
63
+ ```shell
64
+ pip install fpathlib
65
+ ```
66
+
67
+ The `fpathlib.ext.polars` extension additionally requires `polars`, which
68
+ is not installed by `fpathlib` itself:
69
+
70
+ ```shell
71
+ pip install polars
72
+ ```
73
+
74
+ Documentation
75
+ -------------
76
+
77
+ Full API documentation is in `docs/`; build it locally with
78
+ `scripts/docs.sh` (requires the `dev` extras: `pip install -e .[dev]`).
@@ -0,0 +1,61 @@
1
+ fpathlib
2
+ ========
3
+
4
+ A Python package for adding metadata to file paths.
5
+
6
+ `fpathlib` combines file paths with the metadata encoded in their names. It
7
+ does this with an f-string-like path pattern -- `FPath` -- whose
8
+ `{variable}` fields are captured out of every matching path on disk.
9
+
10
+ ```python
11
+ from fpathlib import expand_fpath
12
+
13
+ # Given files like data/tr1/output/0/job2.log, data/tr2/output/1/job0.log, ...
14
+ expanded = expand_fpath("data/tr{trajectory:d}/output/{replica:d}/job{job:d}.log")
15
+
16
+ for path in expanded:
17
+ print(path, path.metadata)
18
+ # data/tr1/output/0/job2.log {'trajectory': 1, 'replica': 0, 'job': 2}
19
+ # data/tr2/output/1/job0.log {'trajectory': 2, 'replica': 1, 'job': 0}
20
+ ```
21
+
22
+ Combine the metadata for every matched path into a single table:
23
+
24
+ ```python
25
+ df = expanded.to_polars()
26
+ ```
27
+
28
+ `fpathlib.ext.polars` goes a step further: it wraps `polars`'s own
29
+ `read_csv`/`scan_csv`/`read_txt`/`scan_txt` so that an expandable path
30
+ pattern is accepted directly, and the resulting DataFrame or LazyFrame comes
31
+ back with the metadata already joined in.
32
+
33
+ ```python
34
+ import fpathlib.ext.polars as pl
35
+
36
+ df = pl.read_csv(
37
+ "data/tr{trajectory:d}/output/{replica:d}/job{job:d}.log",
38
+ has_header=False,
39
+ )
40
+ # df has columns "column_1", ..., plus "trajectory", "replica", "job"
41
+ ```
42
+
43
+ Installation
44
+ ------------
45
+
46
+ ```shell
47
+ pip install fpathlib
48
+ ```
49
+
50
+ The `fpathlib.ext.polars` extension additionally requires `polars`, which
51
+ is not installed by `fpathlib` itself:
52
+
53
+ ```shell
54
+ pip install polars
55
+ ```
56
+
57
+ Documentation
58
+ -------------
59
+
60
+ Full API documentation is in `docs/`; build it locally with
61
+ `scripts/docs.sh` (requires the `dev` extras: `pip install -e .[dev]`).
@@ -0,0 +1,7 @@
1
+
2
+ 1. Tests are a mix between automated (in loading different test cases) and hardcoded (in asserting the expected output). If we move to other testcases, this will not work.
3
+ 2. Should multiple fpaths be supported, for instance, pl.scan_txt(["{a}/fname", "{a}/{b}/fname"]) ?
4
+
5
+
6
+
7
+
@@ -0,0 +1,36 @@
1
+ API Reference
2
+ =============
3
+
4
+ Path
5
+ ----
6
+
7
+ .. autoclass:: fpathlib.Path
8
+ :members:
9
+ :undoc-members:
10
+ :show-inheritance:
11
+
12
+ FPath and ExpandedFPath
13
+ -----------------------
14
+
15
+ .. autoclass:: fpathlib.FPath
16
+ :members:
17
+ :undoc-members:
18
+
19
+ .. autoclass:: fpathlib.ExpandedFPath
20
+ :members:
21
+ :undoc-members:
22
+
23
+ Expanding paths
24
+ ----------------
25
+
26
+ .. autofunction:: fpathlib.expand_fpath
27
+
28
+ .. autofunction:: fpathlib.expand_fpath_decorator
29
+
30
+ .. autofunction:: fpathlib.is_expandable
31
+
32
+ Polars extension
33
+ -----------------
34
+
35
+ .. automodule:: fpathlib.ext.polars
36
+ :members: read_csv, read_txt, scan_csv, scan_parquet, scan_txt
@@ -20,8 +20,12 @@ release = '0.1.0'
20
20
 
21
21
  extensions = [
22
22
  "sphinx.ext.autodoc",
23
+ "sphinx.ext.napoleon",
23
24
  ]
24
25
 
26
+ napoleon_numpy_docstring = True
27
+ napoleon_google_docstring = False
28
+
25
29
  templates_path = ['_templates']
26
30
  exclude_patterns = []
27
31
 
@@ -0,0 +1,66 @@
1
+ fpathlib
2
+ ========
3
+
4
+ fpathlib combines file paths with the metadata encoded in their names.
5
+
6
+ The core idea is an f-string-like path pattern -- an :class:`~fpathlib.FPath`
7
+ -- whose ``{variable}`` fields are captured out of every matching path on
8
+ disk, producing an :class:`~fpathlib.ExpandedFPath`: a collection of
9
+ :class:`~fpathlib.Path` objects, each carrying the metadata parsed from its
10
+ own filename.
11
+
12
+ .. code-block:: python
13
+
14
+ from fpathlib import expand_fpath
15
+
16
+ # Given files like data/tr1/output/0/job2.log, data/tr2/output/1/job0.log, ...
17
+ expanded = expand_fpath("data/tr{trajectory:d}/output/{replica:d}/job{job:d}.log")
18
+
19
+ for path in expanded:
20
+ print(path, path.metadata)
21
+ # data/tr1/output/0/job2.log {'trajectory': 1, 'replica': 0, 'job': 2}
22
+ # data/tr2/output/1/job0.log {'trajectory': 2, 'replica': 1, 'job': 0}
23
+
24
+ Combine the metadata for every matched path into a single table with
25
+ :meth:`~fpathlib.ExpandedFPath.to_polars`:
26
+
27
+ .. code-block:: python
28
+
29
+ df = expanded.to_polars()
30
+
31
+ :mod:`fpathlib.ext.polars` goes a step further: it wraps ``polars``'s own
32
+ ``read_csv``/``scan_csv``/``read_txt``/``scan_txt`` so that an expandable
33
+ path pattern is accepted directly, and the resulting DataFrame or LazyFrame
34
+ comes back with the metadata already joined in.
35
+
36
+ .. code-block:: python
37
+
38
+ import fpathlib.ext.polars as pl
39
+
40
+ df = pl.read_csv(
41
+ "data/tr{trajectory:d}/output/{replica:d}/job{job:d}.log",
42
+ has_header=False,
43
+ )
44
+ # df has columns "column_1", ..., plus "trajectory", "replica", "job"
45
+
46
+ Installation
47
+ ------------
48
+
49
+ .. code-block:: shell
50
+
51
+ pip install fpathlib
52
+
53
+ The ``fpathlib.ext.polars`` extension additionally requires ``polars``,
54
+ which is not installed by :mod:`fpathlib` itself:
55
+
56
+ .. code-block:: shell
57
+
58
+ pip install polars
59
+
60
+ API Reference
61
+ -------------
62
+
63
+ .. toctree::
64
+ :maxdepth: 2
65
+
66
+ api
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [tool.setuptools_scm]
6
6
  write_to = "src/fpathlib/_version.py"
7
- version_scheme = "post-release"
7
+ version_scheme = "guess-next-dev"
8
8
  local_scheme = "no-local-version"
9
9
 
10
10
  [project]
@@ -13,13 +13,14 @@ dynamic = ["version"]
13
13
  description = "A package to combine paths with metadata"
14
14
  authors = [{ name="C. Lockhart", email="clockha2@gmu.edu" }]
15
15
  readme = "README.md"
16
- requires-python = ">=3.9"
16
+ requires-python = ">=3.12"
17
17
  dependencies = [
18
18
  "parse",
19
19
  ]
20
20
 
21
21
  [project.optional-dependencies]
22
- dev = ["pytest", "black", "sphinx"]
22
+ dev = ["pytest", "black", "sphinx", "furo", "polars"]
23
23
 
24
24
  [tool.setuptools.packages.find]
25
25
  where = ["src"]
26
+ exclude = ["*__pycache__*"]
@@ -0,0 +1,3 @@
1
+ source scripts/docs.sh
2
+ source scripts/tag.sh "patch"
3
+ source scripts/pypi.sh
@@ -0,0 +1,3 @@
1
+ cd docs
2
+ make html
3
+ cd ..
@@ -0,0 +1,20 @@
1
+ allow_dev=0
2
+ if [ "$1" = "dev" ]
3
+ then
4
+ allow_dev=1
5
+ fi
6
+
7
+ python3 -m build
8
+
9
+ dev_artifacts=$(ls dist/ | grep -c '\.dev[0-9]')
10
+ if [ $allow_dev -eq 0 ] && [ "$dev_artifacts" != "0" ]
11
+ then
12
+ echo "built version is a dev version (tag likely doesn't point at a distinct commit), not uploading to pypi"
13
+ rm -r dist
14
+ rm -r src/fpathlib.egg-info
15
+ return
16
+ fi
17
+
18
+ twine upload --verbose dist/*
19
+ rm -r dist
20
+ rm -r src/fpathlib.egg-info
@@ -0,0 +1,33 @@
1
+ set -e
2
+
3
+ m=$1
4
+
5
+ tag=$(git describe --tags --abbrev=0)
6
+ parts=(${tag//./ })
7
+ if [ "$m" == "major" ]
8
+ then
9
+ parts[0]=$((parts[0]+1))
10
+ parts[1]=0
11
+ parts[2]=0
12
+ elif [ "$m" == "minor" ]
13
+ then
14
+ parts[1]=$((parts[1]+1))
15
+ parts[2]=0
16
+ elif [ "$m" == "patch" ]
17
+ then
18
+ parts[2]=$((parts[2]+1))
19
+ else
20
+ echo "must specify major, minor, or patch"
21
+ return
22
+ fi
23
+ tag="${parts[0]}.${parts[1]}.${parts[2]}"
24
+
25
+ git add -A
26
+ git commit --allow-empty -m "tag $tag"
27
+ git push origin main
28
+
29
+ git checkout main
30
+ git pull origin main
31
+
32
+ git tag $tag
33
+ git push origin $tag
@@ -0,0 +1,16 @@
1
+ from fpathlib.path import Path
2
+ from fpathlib.fpath import FPath, ExpandedFPath
3
+ from fpathlib.expand import (
4
+ expand_fpath,
5
+ expand_fpath_decorator,
6
+ is_expandable,
7
+ )
8
+
9
+ __all__ = [
10
+ "Path",
11
+ "FPath",
12
+ "ExpandedFPath",
13
+ "expand_fpath",
14
+ "expand_fpath_decorator",
15
+ "is_expandable",
16
+ ]
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.1.2.post0'
22
- __version_tuple__ = version_tuple = (0, 1, 2, 'post0')
21
+ __version__ = version = '0.1.3'
22
+ __version_tuple__ = version_tuple = (0, 1, 3)
23
23
 
24
- __commit_id__ = commit_id = 'g780142e93'
24
+ __commit_id__ = commit_id = 'g02b650d92'
@@ -0,0 +1,106 @@
1
+ from functools import wraps
2
+ import parse
3
+
4
+ from .fpath import ExpandedFPath, FPath
5
+
6
+
7
+ def expand_fpath(fpath, *, exclude_path_patterns=None, require_metadata=True):
8
+ """
9
+ Use an f-string to extract out a collection of paths, where the f-string variables
10
+ are captured and stored along the path name. This is a convenience function that
11
+ simply creates an :obj:`FPath` and calls its :meth:`.expand` method.
12
+
13
+ Parameters
14
+ ----------
15
+ fpath : :obj:`str`
16
+ An f-string path, where the variables are captured and stored along the path
17
+ name.
18
+ exclude_path_patterns : :obj:`str` or :obj:`Iterable`[:obj:`str`]
19
+ Exclude paths that match the supplied pattern. (Default: None).
20
+ require_metadata : :obj:`bool`
21
+ Require that all paths identified must have found metadata. (Default: True).
22
+
23
+ Returns
24
+ -------
25
+ :obj:`.ExpandedFPath`
26
+ """
27
+
28
+ return FPath(fpath).expand(
29
+ exclude_path_patterns=exclude_path_patterns,
30
+ require_metadata=require_metadata,
31
+ )
32
+
33
+
34
+ def expand_fpath_decorator(f=None, require_expandable=True, post_process=None):
35
+ """
36
+ Decorator for :func:`.expand_fpath`.
37
+
38
+ Parameters
39
+ ----------
40
+ f : :obj:`callable`
41
+ A function that takes an :obj:`.ExpandedFPath` as its first argument.
42
+ post_process : :obj:`callable`
43
+ A function that takes the output of `f` and the :obj:`.ExpandedFPath`.
44
+ (Default: None).
45
+ """
46
+
47
+ def decorator(f):
48
+ @wraps(f)
49
+ def wrapper(fpath, *args, **kwargs):
50
+ # If fpath is an :obj:`ExpandedFPath`, just call f with it.
51
+ if isinstance(fpath, ExpandedFPath):
52
+ expanded_fpath = fpath
53
+ result = f(fpath, *args, **kwargs)
54
+
55
+ # Otherwise, expand fpath and call f with the result.
56
+ else:
57
+ # What happens if fpath is not expandable?
58
+ # If require_expandable is True, raise an error.
59
+ # Otherwise, just call f with the original fpath.
60
+ if not is_expandable(fpath):
61
+ if require_expandable:
62
+ msg = f"fpath not expandable: '{fpath}'"
63
+ raise ValueError(msg)
64
+ return f(fpath, *args, **kwargs)
65
+
66
+ # We know fpath is expandable, so we can expand it and call f
67
+ exclude_path_patterns = kwargs.pop("exclude_path_patterns", None)
68
+ require_metadata = kwargs.pop("require_metadata", True)
69
+ expanded_fpath = expand_fpath(
70
+ fpath,
71
+ exclude_path_patterns=exclude_path_patterns,
72
+ require_metadata=require_metadata,
73
+ )
74
+ result = f(expanded_fpath, *args, **kwargs)
75
+
76
+ # If post_process is provided, call it with the result and the expanded_fpath.
77
+ if post_process is not None:
78
+ result = post_process(result, expanded_fpath)
79
+
80
+ return result
81
+
82
+ return wrapper
83
+
84
+ if f is None:
85
+ return decorator
86
+ else:
87
+ return decorator(f)
88
+
89
+ def is_expandable(fpath):
90
+ """
91
+ Check if expandable.
92
+
93
+ Parameters
94
+ ----------
95
+ fpath : :obj:`str`
96
+
97
+ Returns
98
+ -------
99
+ :obj:`bool`
100
+ """
101
+
102
+ try:
103
+ parser = parse.compile(str(fpath))
104
+ return bool(parser.named_fields)
105
+ except TypeError:
106
+ return False