1414import textwrap
1515from collections import abc as cabc
1616from functools import update_wrapper , wraps
17- from typing import Any , Callable , Collection , List , Mapping , Tuple
17+ from typing import Any , Callable , Collection , List , Mapping , Sequence , Tuple
1818
1919from boltons .setutils import IndexedSet as iset
2020
@@ -202,11 +202,15 @@ def reparse_operation_data(
202202 return name , jsonp_ize_all (needs ), jsonp_ize_all (provides ), aliases
203203
204204
205- def _spread_sideffects (
206- deps : Collection [str ],
205+ def _process_dependencies (
206+ deps : Collection [str ], cwd : Sequence [ str ]
207207) -> Tuple [Collection [str ], Collection [str ]]:
208208 """
209- Build fn/op dependencies by stripping/singularizing any :term:`implicit`/:term:`sideffects`.
209+ Strip or singularize any :term:`implicit`/:term:`sideffects` and apply CWD.
210+
211+ :param cwd:
212+ the :term:`current-working-document` parts to prepend on each dependency,
213+ turning all as :term:`jsonp`\\ s.
210214
211215 :return:
212216 a x2 tuple ``(op_deps, fn_deps)``, where any instances of
@@ -230,6 +234,20 @@ def _spread_sideffects(
230234 #: The dedupe any `sideffected`.
231235 seen_sideffecteds = set ()
232236
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+
233251 def as_fn_deps (dep ):
234252 """Strip and dedupe any sfxed, drop any sfx and implicit. """
235253 if is_implicit (dep ): # must ignore also `sfxed`s
@@ -246,6 +264,7 @@ def as_fn_deps(dep):
246264 assert deps is not None
247265
248266 if deps :
267+ deps = [prefixed (d ) for d in deps ]
249268 op_deps = iset (nn for n in deps for nn in dep_singularized (n ))
250269 fn_deps = tuple (nn for n in deps for nn in as_fn_deps (n ))
251270 return op_deps , fn_deps
@@ -304,6 +323,7 @@ def __init__(
304323 provides : Items = None ,
305324 aliases : Mapping = None ,
306325 * ,
326+ cwd = None ,
307327 rescheduled = None ,
308328 endured = None ,
309329 parallel = None ,
@@ -317,6 +337,8 @@ def __init__(
317337 See :func:`.operation` for the full documentation of parameters,
318338 study the code for attributes (or read them from rendered sphinx site).
319339 """
340+ from .jsonpointer import jsonp_path
341+
320342 super ().__init__ ()
321343 node_props = node_props = node_props if node_props else {}
322344
@@ -333,10 +355,11 @@ def __init__(
333355 name , needs , provides , aliases = reparse_operation_data (
334356 name , needs , provides , aliases
335357 )
358+ cwd_parts = jsonp_path (cwd ) if cwd else ()
336359
337360 user_needs , user_provides = needs , provides
338- needs , _fn_needs = _spread_sideffects (needs )
339- provides , _fn_provides = _spread_sideffects (provides )
361+ needs , _fn_needs = _process_dependencies (needs , cwd_parts )
362+ provides , _fn_provides = _process_dependencies (provides , cwd_parts )
340363 alias_dst = aliases and tuple (dst for _src , dst in aliases )
341364 provides = iset ((* provides , * alias_dst ))
342365
@@ -398,6 +421,9 @@ def __init__(
398421 #:
399422 #: You cannot alias an :term:`alias`.
400423 self .aliases = aliases
424+ #: The :term:`current-working-document`, when defined, all non-root `dependencies`
425+ # become :term:`jsonp` and are prefixed with this.
426+ self .cwd = cwd
401427 #: If true, underlying *callable* may produce a subset of `provides`,
402428 #: and the :term:`plan` must then :term:`reschedule` after the operation
403429 #: has executed. In that case, it makes more sense for the *callable*
@@ -487,6 +513,7 @@ def withset(
487513 provides : Items = ...,
488514 aliases : Mapping = ...,
489515 * ,
516+ cwd = ...,
490517 rescheduled = ...,
491518 endured = ...,
492519 parallel = ...,
@@ -921,6 +948,7 @@ def operation(
921948 provides : Items = UNSET ,
922949 aliases : Mapping = UNSET ,
923950 * ,
951+ cwd = UNSET ,
924952 rescheduled = UNSET ,
925953 endured = UNSET ,
926954 parallel = UNSET ,
@@ -1002,6 +1030,9 @@ def operation(
10021030
10031031 :param aliases:
10041032 an optional mapping of `provides` to additional ones
1033+ :param cwd:
1034+ The :term:`current-working-document`, when given, all non-root `dependencies`
1035+ become :term:`jsonp` and are prefixed with this.
10051036 :param rescheduled:
10061037 If true, underlying *callable* may produce a subset of `provides`,
10071038 and the :term:`plan` must then :term:`reschedule` after the operation
0 commit comments