Current Situation
The cmd= parameter of Target specifies a function with the signature
Callable[Concatenate[T, ...], None]
and the parameters are the target's .item as well as the items of all dependencies.
The state= parameter wants a function with signature
Callable[[T], str]
and will only ever see the target's .item and nothing else.
The original idea was that the state function should look only at the target and nothing else. Though when the target defines, for example, only a subset of files in a directory, the target directory is not enough to compute the state. Some filter, for example a glob pattern, is also needed to specify the subset.
Even worse, in case we want to copy a subset of files from directory D to directory T, the filter must be applied first to D, the files must be mapped to T and then the state of the resulting files can be computed.
It seems natural to provide the glob pattern as well as D as dependencies, because, obviously, if one of them changes, the target must be re-computed.
By passing these two dependencies also to the state generating function, it has all necessary pieces ready to compute the state over the subset of files.
Requirement
Pass the target's .item as well as all dependency items to state computation functions.
Pro and Cons
- 👎 The experience gathered so far suggests that state computation functions actually just need the target item. The use case above is rather infrequent. Passing unused arguments to most state computation functions seems ugly.
- 👎Further, a
lambda or one-line def can easily curry the extra arguments onto a function to create the one-parameter function needed
- 👍The solution would avoid the ugly lambda or def one-liner
Alternative 1
For the, so far, one use case, a target file set derived from a source file set, define a class, say PathMapper with these ingredients:
- target
Path
- source
Path
- rglob pattern to be applied to source
- mapping function to transform each
Path found to one below the target
Then we could have Target[PathMapper] and the state computation function would have all it needs.
👎Downside: source and rglob are still natural dependencies, so both are mentioned twice, once in the PathMapper and once in the dependency list. Not using the identical objects in both places will end up in fun debugging sessions.
Alternative 2
Go back to providing not the target's .item but the Target itself to the state computation function. Most of them will just grab the item and be done, but where necessary, as in the use case above, the can access the dependency to conjure up some magic.
Currently favored 👍.
Alternative 3
Like 2, but allow state computation functions which accept either an item or a Target. Call them as needed after using inspect.* to figure out which type it is.
# Current Situation
The `cmd=` parameter of `Target` specifies a function with the signature
`Callable[Concatenate[T, ...], None]`
and the parameters are the target's `.item` as well as the items of all dependencies.
The `state=` parameter wants a function with signature
`Callable[[T], str]`
and will only ever see the target's `.item` and nothing else.
The original idea was that the state function should look only at the target and nothing else. Though when the target defines, for example, only a subset of files in a directory, the target directory is not enough to compute the state. Some filter, for example a glob pattern, is also needed to specify the subset.
Even worse, in case we want to copy a subset of files from directory `D` to directory `T`, the filter must be applied first to `D`, the files must be mapped to `T` and then the state of the resulting files can be computed.
It seems natural to provide the glob pattern as well as `D` as dependencies, because, obviously, if one of them changes, the target must be re-computed.
By passing these two dependencies also to the state generating function, it has all necessary pieces ready to compute the state over the subset of files.
# Requirement
Pass the target's `.item` as well as all dependency items to state computation functions.
### Pro and Cons
- 👎 The experience gathered so far suggests that state computation functions actually just need the target item. The use case above is rather infrequent. Passing unused arguments to most state computation functions seems ugly.
- 👎Further, a `lambda` or one-line `def` can easily curry the extra arguments onto a function to create the one-parameter function needed
- 👍The solution would avoid the ugly lambda or def one-liner
## Alternative 1
For the, so far, one use case, a target file set derived from a source file set, define a class, say `PathMapper` with these ingredients:
- target `Path`
- source `Path`
- rglob pattern to be applied to source
- mapping function to transform each `Path` found to one below the target
Then we could have `Target[PathMapper]` and the state computation function would have all it needs.
👎Downside: source and rglob are still natural dependencies, so both are mentioned twice, once in the `PathMapper` and once in the dependency list. Not using the identical objects in both places will end up in fun debugging sessions.
## Alternative 2
Go back to providing not the target's `.item` but the `Target` itself to the state computation function. Most of them will just grab the item and be done, but where necessary, as in the use case above, the can access the dependency to conjure up some magic.
Currently favored 👍.
## Alternative 3
Like 2, but allow state computation functions which accept either an item or a `Target`. Call them as needed after using `inspect.*` to figure out which type it is.