fpathlib 0.1.4.dev12__tar.gz → 0.1.5__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.
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/.gitignore +1 -0
- {fpathlib-0.1.4.dev12/src/fpathlib.egg-info → fpathlib-0.1.5}/PKG-INFO +1 -1
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/conda-recipe/meta.yaml +2 -2
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/scripts/pypi.sh +8 -1
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib/__init__.py +2 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib/_version.py +3 -3
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib/expand.py +51 -14
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib/ext/polars.py +1 -1
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib/fpath.py +53 -14
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5/src/fpathlib.egg-info}/PKG-INFO +1 -1
- fpathlib-0.1.5/src/fpathlib.egg-info/scm_version.json +8 -0
- fpathlib-0.1.4.dev12/src/fpathlib.egg-info/scm_version.json +0 -8
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/LICENSE +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/MANIFEST.in +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/README.md +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/TODO.txt +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/docs/Makefile +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/docs/make.bat +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/docs/source/api.rst +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/docs/source/conf.py +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/docs/source/index.rst +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/pyproject.toml +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/scripts/conda.sh +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/scripts/deploy.sh +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/scripts/docs.sh +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/scripts/tag.sh +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/setup.cfg +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib/ext/__init__.py +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib/path.py +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib/utils.py +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib.egg-info/SOURCES.txt +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib.egg-info/dependency_links.txt +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib.egg-info/requires.txt +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib.egg-info/scm_file_list.json +0 -0
- {fpathlib-0.1.4.dev12 → fpathlib-0.1.5}/src/fpathlib.egg-info/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{% set name = "fpathlib" %}
|
|
2
|
-
{% set version = "0.1.
|
|
2
|
+
{% set version = "0.1.4" %}
|
|
3
3
|
|
|
4
4
|
package:
|
|
5
5
|
name: {{ name|lower }}
|
|
@@ -7,7 +7,7 @@ package:
|
|
|
7
7
|
|
|
8
8
|
source:
|
|
9
9
|
url: https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/fpathlib-{{ version }}.tar.gz
|
|
10
|
-
sha256:
|
|
10
|
+
sha256: 8ff44332a465c2adb5c45f94d6ee79c958fb50c39e896b16734d0d8208026c77
|
|
11
11
|
|
|
12
12
|
build:
|
|
13
13
|
noarch: python
|
|
@@ -21,7 +21,14 @@ python3 -m build
|
|
|
21
21
|
# 0.1.3/0.1.2 tag-collision incident slipped past a git-describe check even
|
|
22
22
|
# though the build itself came out as a .devN), inspect what actually got
|
|
23
23
|
# built. This is the real signal of whether the release is clean.
|
|
24
|
-
|
|
24
|
+
#
|
|
25
|
+
# `grep -c` exits 1 (not just prints "0") when it finds zero matches --
|
|
26
|
+
# with `set -e` active (deploy.sh sets it, and this script is sourced into
|
|
27
|
+
# that same shell), that silently killed the whole deploy right here for
|
|
28
|
+
# every *clean* release build (the exact case with 0 .dev files), before
|
|
29
|
+
# ever reaching twine upload. `|| true` keeps the count without letting
|
|
30
|
+
# grep's "no matches" exit status abort the script.
|
|
31
|
+
dev_artifacts=$(ls dist/ | grep -c '\.dev[0-9]' || true)
|
|
25
32
|
if [ $allow_dev -eq 0 ] && [ "$dev_artifacts" != "0" ]
|
|
26
33
|
then
|
|
27
34
|
echo "built version is a dev version (tag doesn't point at a clean, distinct commit -- check 'git describe --tags --long' and 'git status'), not uploading to pypi"
|
|
@@ -2,6 +2,7 @@ from fpathlib.path import Path
|
|
|
2
2
|
from fpathlib.fpath import FPath, ExpandedFPath
|
|
3
3
|
from fpathlib.expand import (
|
|
4
4
|
expand_fpath,
|
|
5
|
+
iexpand_fpath,
|
|
5
6
|
expand_fpath_decorator,
|
|
6
7
|
is_expandable,
|
|
7
8
|
)
|
|
@@ -11,6 +12,7 @@ __all__ = [
|
|
|
11
12
|
"FPath",
|
|
12
13
|
"ExpandedFPath",
|
|
13
14
|
"expand_fpath",
|
|
15
|
+
"iexpand_fpath",
|
|
14
16
|
"expand_fpath_decorator",
|
|
15
17
|
"is_expandable",
|
|
16
18
|
]
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
21
|
+
__version__ = version = '0.1.5'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 5)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'gae98b27f0'
|
|
@@ -31,7 +31,39 @@ def expand_fpath(fpath, *, exclude_path_patterns=None, require_metadata=True):
|
|
|
31
31
|
)
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def
|
|
34
|
+
def iexpand_fpath(fpath, *, exclude_path_patterns=None, require_metadata=True, errors="raise"):
|
|
35
|
+
"""
|
|
36
|
+
Generator equivalent of :func:`.expand_fpath` -- lazily yields each
|
|
37
|
+
matching :obj:`.Path` instead of building the whole
|
|
38
|
+
:obj:`.ExpandedFPath` up front. This is a convenience function that
|
|
39
|
+
simply creates an :obj:`FPath` and calls its :meth:`.FPath.iexpand`
|
|
40
|
+
method.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
fpath : :obj:`str`
|
|
45
|
+
An f-string path, where the variables are captured and stored along the path
|
|
46
|
+
name.
|
|
47
|
+
exclude_path_patterns : :obj:`str` or :obj:`Iterable`[:obj:`str`]
|
|
48
|
+
Exclude paths that match the supplied pattern. (Default: None).
|
|
49
|
+
require_metadata : :obj:`bool`
|
|
50
|
+
Require that all paths identified must have found metadata. (Default: True).
|
|
51
|
+
errors : :obj:`str`
|
|
52
|
+
How to handle the "no matches" case. See :meth:`.FPath.iexpand`. (Default: "raise").
|
|
53
|
+
|
|
54
|
+
Yields
|
|
55
|
+
------
|
|
56
|
+
:obj:`.Path`
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
return FPath(fpath).iexpand(
|
|
60
|
+
exclude_path_patterns=exclude_path_patterns,
|
|
61
|
+
require_metadata=require_metadata,
|
|
62
|
+
errors=errors,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def expand_fpath_decorator(f=None, require_expandable=False, post_process=None):
|
|
35
67
|
"""
|
|
36
68
|
Decorator for :func:`.expand_fpath`.
|
|
37
69
|
|
|
@@ -39,6 +71,11 @@ def expand_fpath_decorator(f=None, require_expandable=True, post_process=None):
|
|
|
39
71
|
----------
|
|
40
72
|
f : :obj:`callable`
|
|
41
73
|
A function that takes an :obj:`.ExpandedFPath` as its first argument.
|
|
74
|
+
require_expandable : :obj:`bool`
|
|
75
|
+
Whether to require `fpath` to have {} named captures. If False
|
|
76
|
+
(the default), a plain literal path or glob is passed straight
|
|
77
|
+
through to `f` unexpanded, with `post_process` skipped -- there's
|
|
78
|
+
no ExpandedFPath to hand it in that case. (Default: False)
|
|
42
79
|
post_process : :obj:`callable`
|
|
43
80
|
A function that takes the output of `f` and the :obj:`.ExpandedFPath`.
|
|
44
81
|
(Default: None).
|
|
@@ -52,18 +89,8 @@ def expand_fpath_decorator(f=None, require_expandable=True, post_process=None):
|
|
|
52
89
|
expanded_fpath = fpath
|
|
53
90
|
result = f(fpath, *args, **kwargs)
|
|
54
91
|
|
|
55
|
-
#
|
|
56
|
-
|
|
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
|
|
92
|
+
# Expand fpath if it is expandable.
|
|
93
|
+
elif is_expandable(fpath):
|
|
67
94
|
exclude_path_patterns = kwargs.pop("exclude_path_patterns", None)
|
|
68
95
|
require_metadata = kwargs.pop("require_metadata", True)
|
|
69
96
|
expanded_fpath = expand_fpath(
|
|
@@ -73,7 +100,17 @@ def expand_fpath_decorator(f=None, require_expandable=True, post_process=None):
|
|
|
73
100
|
)
|
|
74
101
|
result = f(expanded_fpath, *args, **kwargs)
|
|
75
102
|
|
|
76
|
-
#
|
|
103
|
+
# fpath has no {} captures, so there's no ExpandedFPath to
|
|
104
|
+
# build -- nothing for post_process (e.g. join_metadata) to
|
|
105
|
+
# join metadata from. Call f directly and return immediately,
|
|
106
|
+
# skipping post_process entirely, rather than falling through
|
|
107
|
+
# to it with no expanded_fpath to give it.
|
|
108
|
+
else:
|
|
109
|
+
if require_expandable:
|
|
110
|
+
msg = f"fpath not expandable: '{fpath}'"
|
|
111
|
+
raise ValueError(msg)
|
|
112
|
+
return f(fpath, *args, **kwargs)
|
|
113
|
+
|
|
77
114
|
if post_process is not None:
|
|
78
115
|
result = post_process(result, expanded_fpath)
|
|
79
116
|
|
|
@@ -160,7 +160,7 @@ def scan_parquet(expanded_fpath, *args, **kwargs):
|
|
|
160
160
|
|
|
161
161
|
|
|
162
162
|
# TODO rename expanded_fpath as source
|
|
163
|
-
@expand_fpath_decorator(
|
|
163
|
+
@expand_fpath_decorator(post_process=join_metadata)
|
|
164
164
|
def scan_txt(
|
|
165
165
|
expanded_fpath,
|
|
166
166
|
filter_expr=None,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections.abc import Sequence
|
|
2
|
-
from glob import glob
|
|
2
|
+
from glob import glob, iglob
|
|
3
3
|
import parse
|
|
4
4
|
import re
|
|
5
5
|
|
|
@@ -31,10 +31,19 @@ class FPath:
|
|
|
31
31
|
def __repr__(self):
|
|
32
32
|
return "FPath({!r})".format(self.fpath)
|
|
33
33
|
|
|
34
|
-
def
|
|
34
|
+
def iexpand(self, exclude_path_patterns=None, require_metadata=True, errors="raise"):
|
|
35
35
|
"""
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
Lazily yield each :obj:`.Path` matching the f-string pattern, one at
|
|
37
|
+
a time, instead of building the whole :obj:`.ExpandedFPath` up
|
|
38
|
+
front. Useful when a pattern could match a very large number of
|
|
39
|
+
files and you don't want them all held in memory at once, or want
|
|
40
|
+
to start processing before the full glob finishes walking the
|
|
41
|
+
filesystem. :meth:`.expand` is built on top of this generator.
|
|
42
|
+
|
|
43
|
+
Like any generator function, nothing in the body runs -- including
|
|
44
|
+
argument validation and the wildcard/{} capture check -- until the
|
|
45
|
+
result is first iterated (a `for` loop, `list(...)`, etc.), not at
|
|
46
|
+
the moment :meth:`.iexpand` is called.
|
|
38
47
|
|
|
39
48
|
Parameters
|
|
40
49
|
----------
|
|
@@ -43,13 +52,13 @@ class FPath:
|
|
|
43
52
|
require_metadata : :obj:`bool`
|
|
44
53
|
Require that all paths identified must have found metadata. (Default: True).
|
|
45
54
|
errors : :obj:`str`
|
|
46
|
-
How to handle
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
How to handle the "no matches" case, checked once the pattern is
|
|
56
|
+
fully exhausted. If "raise", then raise an error. If "warn",
|
|
57
|
+
then warn. If "ignore", then do nothing. (Default: "raise").
|
|
49
58
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
:obj:`.
|
|
59
|
+
Yields
|
|
60
|
+
------
|
|
61
|
+
:obj:`.Path`
|
|
53
62
|
"""
|
|
54
63
|
|
|
55
64
|
if errors not in {"raise", "warn", "ignore"}:
|
|
@@ -84,8 +93,8 @@ class FPath:
|
|
|
84
93
|
)
|
|
85
94
|
raise ValueError(msg)
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
for fname in
|
|
96
|
+
n = 0
|
|
97
|
+
for fname in iglob(re.sub(r"\{.*?\}", "*", self.fpath)):
|
|
89
98
|
path = Path(fname)
|
|
90
99
|
if exclude_path_patterns and path.match_any(exclude_path_patterns):
|
|
91
100
|
continue
|
|
@@ -93,9 +102,10 @@ class FPath:
|
|
|
93
102
|
if require_metadata and path.metadata is None:
|
|
94
103
|
msg = f"metadata not found for '{fname}' with '{self.fpath}'"
|
|
95
104
|
raise AttributeError(msg)
|
|
96
|
-
|
|
105
|
+
n += 1
|
|
106
|
+
yield path
|
|
97
107
|
|
|
98
|
-
if
|
|
108
|
+
if n == 0 and errors != "ignore":
|
|
99
109
|
msg = f"no paths found for {self.fpath.__repr__()}"
|
|
100
110
|
if errors == "raise":
|
|
101
111
|
raise IOError(msg)
|
|
@@ -104,6 +114,35 @@ class FPath:
|
|
|
104
114
|
|
|
105
115
|
warnings.warn(msg)
|
|
106
116
|
|
|
117
|
+
def expand(self, exclude_path_patterns=None, require_metadata=True, errors="raise"):
|
|
118
|
+
"""
|
|
119
|
+
Use an f-string to extract out a collection of paths, where the f-string
|
|
120
|
+
variables are captured and stored along the path name.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
exclude_path_patterns : :obj:`str` or :obj:`Iterable`[:obj:`str`]
|
|
125
|
+
Exclude paths that match the supplied pattern. (Default: None).
|
|
126
|
+
require_metadata : :obj:`bool`
|
|
127
|
+
Require that all paths identified must have found metadata. (Default: True).
|
|
128
|
+
errors : :obj:`str`
|
|
129
|
+
How to handle errors. If "raise", then raise an error. If "warn", then warn
|
|
130
|
+
and return an empty collection. If "ignore", then ignore the error and
|
|
131
|
+
return an empty collection. (Default: "raise").
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
:obj:`.ExpandedFPath`
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
paths = list(
|
|
139
|
+
self.iexpand(
|
|
140
|
+
exclude_path_patterns=exclude_path_patterns,
|
|
141
|
+
require_metadata=require_metadata,
|
|
142
|
+
errors=errors,
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
|
|
107
146
|
return ExpandedFPath(paths=paths, fpath=self)
|
|
108
147
|
|
|
109
148
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|