Skip to content

Commit b9a196f

Browse files
committed
FEAT(FnOp) CWD to jsonp_ize all dependencies ...
+ doc(modif) explain why jsonp_ize() checks type
1 parent 805b809 commit b9a196f

File tree

4 files changed

+58
-32
lines changed

4 files changed

+58
-32
lines changed

graphtik/fnop.py

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,35 @@ def is_list_of_2(i):
113113
return i
114114

115115

116-
def jsonp_ize_all(deps):
116+
def prefixed(dep, cwd):
117+
"""
118+
Converts `dep` into a :term:`jsonp` and prepends `prefix` (unless `dep` was rooted).
119+
120+
TODO: make `prefixed` a TOP_LEVEL `modifier`.
121+
"""
122+
from .jsonpointer import json_pointer, jsonp_path, prepend_parts
123+
from .modifier import jsonp_ize
124+
125+
if not dep or is_pure_sfx(dep):
126+
pass
127+
elif cwd:
128+
parts = prepend_parts(cwd, jsonp_path(dep_stripped(dep)))
129+
dep = dep_renamed(dep, json_pointer(parts), jsonp=parts)
130+
else:
131+
dep = jsonp_ize(dep)
132+
133+
return dep
134+
135+
136+
def jsonp_ize_all(deps, cwd: Sequence[str]):
117137
"""Auto-convert deps with slashes as :term:`jsonp` (unless ``no_jsonp``). """
118138
if deps:
119-
deps = tuple(jsonp_ize(dep) for dep in deps)
139+
deps = tuple(prefixed(dep, cwd) for dep in deps)
120140
return deps
121141

122142

123143
def reparse_operation_data(
124-
name, needs, provides, aliases=()
144+
name, needs, provides, aliases=(), cwd: Sequence[str] = None
125145
) -> Tuple[str, Collection[str], Collection[str], Collection[Tuple[str, str]]]:
126146
"""
127147
Validate & reparse operation data as lists.
@@ -132,26 +152,40 @@ def reparse_operation_data(
132152
As a separate function to be reused by client building operations,
133153
to detect errors early.
134154
"""
155+
from .jsonpointer import jsonp_path
156+
135157
if name is not None and not isinstance(name, str):
136158
raise TypeError(f"Non-str `name` given: {name}")
137159

160+
cwd_parts = jsonp_path(cwd) if cwd else ()
161+
138162
# Allow single string-value for needs parameter
139163
needs = astuple(needs, "needs", allowed_types=cabc.Collection)
140164
if not all(isinstance(i, str) for i in needs):
141165
raise TypeError(f"All `needs` must be str, got: {needs!r}")
166+
needs = jsonp_ize_all(needs, cwd_parts)
142167

143168
# Allow single value for provides parameter
144169
provides = astuple(provides, "provides", allowed_types=cabc.Collection)
145170
if not all(isinstance(i, str) for i in provides):
146171
raise TypeError(f"All `provides` must be str, got: {provides!r}")
172+
provides = jsonp_ize_all(provides, cwd_parts)
147173

148174
aliases = as_renames(aliases, "aliases")
149175
if aliases:
176+
## Sanity checks, or `jsonp_ize_all()` would fail.
177+
#
150178
if not all(
151179
src and isinstance(src, str) and dst and isinstance(dst, str)
152180
for src, dst in aliases
153181
):
154182
raise TypeError(f"All `aliases` must be non-empty str, got: {aliases!r}")
183+
184+
# XXX: Why jsonp_ize here? (and not everywhere, or nowhere in fnop?)
185+
aliases = [
186+
(prefixed(src, cwd_parts), prefixed(dst, cwd_parts)) for src, dst in aliases
187+
]
188+
155189
if any(1 for src, dst in aliases if dst in provides):
156190
bad = ", ".join(
157191
f"{src} -> {dst}" for src, dst in aliases if dst in provides
@@ -160,8 +194,6 @@ def reparse_operation_data(
160194
f"The `aliases` [{bad}] clash with existing provides in {list(provides)}!"
161195
)
162196

163-
# XXX: Why jsonp_ize here? (and not everywhere, or nowhere in fnop?)
164-
aliases = [(jsonp_ize(src), jsonp_ize(dst)) for src, dst in aliases]
165197
aliases_src = iset(src for src, _dst in aliases)
166198
all_provides = iset(provides) | (dep_stripped(d) for d in provides)
167199

@@ -199,18 +231,18 @@ def reparse_operation_data(
199231
"\n Simply add any extra `implicits` in the `provides`."
200232
)
201233

202-
return name, jsonp_ize_all(needs), jsonp_ize_all(provides), aliases
234+
return name, needs, provides, aliases
203235

204236

205237
def _process_dependencies(
206-
deps: Collection[str], cwd: Sequence[str]
238+
deps: Collection[str],
207239
) -> Tuple[Collection[str], Collection[str]]:
208240
"""
209241
Strip or singularize any :term:`implicit`/:term:`sideffects` and apply CWD.
210242
211243
:param cwd:
212-
the :term:`current-working-document` parts to prepend on each dependency,
213-
turning all as :term:`jsonp`\\s.
244+
The :term:`current-working-document`, when given, all non-root `dependencies`
245+
(`needs`, `provides` & `aliases`) become :term:`jsonp`\\s, prefixed with this.
214246
215247
:return:
216248
a x2 tuple ``(op_deps, fn_deps)``, where any instances of
@@ -234,20 +266,6 @@ def _process_dependencies(
234266
#: The dedupe any `sideffected`.
235267
seen_sideffecteds = set()
236268

237-
def prefixed(dep):
238-
"""
239-
Converts `dep` into a :term:`jsonp` and prepends `prefix` (unless `dep` was rooted).
240-
241-
TODO: make `prefixed` a TOP_LEVEL `modifier`.
242-
"""
243-
from .jsonpointer import jsonp_path, json_pointer, prepend_parts
244-
245-
if cwd and not is_pure_sfx(dep):
246-
parts = prepend_parts(cwd, jsonp_path(dep_stripped(dep)))
247-
dep = dep_renamed(dep, json_pointer(parts), jsonp=parts)
248-
249-
return dep
250-
251269
def as_fn_deps(dep):
252270
"""Strip and dedupe any sfxed, drop any sfx and implicit. """
253271
if is_implicit(dep): # must ignore also `sfxed`s
@@ -264,7 +282,6 @@ def as_fn_deps(dep):
264282
assert deps is not None
265283

266284
if deps:
267-
deps = [prefixed(d) for d in deps]
268285
op_deps = iset(nn for n in deps for nn in dep_singularized(n))
269286
fn_deps = tuple(nn for n in deps for nn in as_fn_deps(n))
270287
return op_deps, fn_deps
@@ -353,13 +370,12 @@ def __init__(
353370
name = func_name(fn, None, mod=0, fqdn=0, human=0, partials=1)
354371
## Overwrite reparsed op-data.
355372
name, needs, provides, aliases = reparse_operation_data(
356-
name, needs, provides, aliases
373+
name, needs, provides, aliases, cwd
357374
)
358-
cwd_parts = jsonp_path(cwd) if cwd else ()
359375

360376
user_needs, user_provides = needs, provides
361-
needs, _fn_needs = _process_dependencies(needs, cwd_parts)
362-
provides, _fn_provides = _process_dependencies(provides, cwd_parts)
377+
needs, _fn_needs = _process_dependencies(needs)
378+
provides, _fn_provides = _process_dependencies(provides)
363379
alias_dst = aliases and tuple(dst for _src, dst in aliases)
364380
provides = iset((*provides, *alias_dst))
365381

@@ -1032,7 +1048,7 @@ def operation(
10321048
an optional mapping of `provides` to additional ones
10331049
:param cwd:
10341050
The :term:`current-working-document`, when given, all non-root `dependencies`
1035-
become :term:`jsonp` and are prefixed with this.
1051+
(`needs`, `provides` & `aliases`) become :term:`jsonp`\\s, prefixed with this.
10361052
:param rescheduled:
10371053
If true, underlying *callable* may produce a subset of `provides`,
10381054
and the :term:`plan` must then :term:`reschedule` after the operation

graphtik/modifier.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,8 +470,8 @@ def is_varargish(dep) -> bool:
470470

471471

472472
def jsonp_ize(dep):
473-
"""Parse dep as :term:`jsonp` (unless it has been modified with ``jsnop=False``). """
474-
return modify(dep) if "/" in dep and type(dep) is str else dep
473+
"""Parse dep as :term:`jsonp` (unless modified with ``jsnop=False``) or is pure sfx. """
474+
return modify(dep) if "/" in dep and type(dep) is str else dep # sfxed-deps already
475475

476476

477477
def get_jsonp(dep) -> Union[List[str], None]:

graphtik/pipeline.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ def __init__(
178178
renamer,
179179
excludes,
180180
)
181+
# TODO: implement `cwd` also for whole pipelines.
181182
self.name, self.needs, self.provides, _aliases = reparse_operation_data(
182183
self.name, self.net.needs, self.net.provides
183184
)

test/test_op.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ def test_cwd():
440440
vcat("vc"),
441441
],
442442
provides=["A/B", "C", "/R"],
443+
aliases=[("A/B", "aa"), ("C", "CC"), ("/R", "RR")],
443444
cwd="root",
444445
)
445446
exp = """
@@ -456,7 +457,15 @@ def test_cwd():
456457
sfxed('root/s2'($),
457458
's22'),
458459
'root/vc'($)],
459-
provides=['root/A/B'($), 'root/C'($), '/R'($)],
460+
provides=['root/A/B'($),
461+
'root/C'($),
462+
'/R'($),
463+
'root/aa'($),
464+
'root/CC'($),
465+
'root/RR'($)],
466+
aliases=[('root/A/B'($), 'root/aa'($)),
467+
('root/C'($), 'root/CC'($)),
468+
('/R'($), 'root/RR'($))],
460469
fn='str')
461470
"""
462471
assert oneliner(op) == oneliner(exp)

0 commit comments

Comments
 (0)