|
35 | 35 | EnsurePath,
|
36 | 36 | EnsureURL,
|
37 | 37 | EnsureValue,
|
| 38 | + WithDescription, |
38 | 39 | )
|
39 | 40 | from datalad_next.constraints.dataset import EnsureDataset
|
40 | 41 | from datalad_next.url_operations.any import AnyUrlOperations
|
@@ -101,37 +102,64 @@ class Download(ValidatedInterface):
|
101 | 102 | # The special value '-' is used to indicate stdout
|
102 | 103 | # if given as a single string, we support single-space-delimited items:
|
103 | 104 | # "<url> <path>"
|
104 |
| - url2path_constraint = EnsureMapping( |
105 |
| - key=url_constraint, |
106 |
| - value=EnsureValue('-') | EnsurePath(), |
107 |
| - delimiter=' ', |
108 |
| - # we disallow length-2 sequences to be able to distinguish from |
109 |
| - # a length-2 list of URLs. |
110 |
| - # the key issue is the flexibility of EnsurePath -- pretty much |
111 |
| - # anything could be a valid unix path |
112 |
| - allow_length2_sequence=False, |
| 105 | + url2path_constraint = WithDescription( |
| 106 | + EnsureMapping( |
| 107 | + key=url_constraint, |
| 108 | + value=EnsureValue('-') | EnsurePath(), |
| 109 | + delimiter=' ', |
| 110 | + # we disallow length-2 sequences to be able to distinguish from |
| 111 | + # a length-2 list of URLs. |
| 112 | + # the key issue is the flexibility of EnsurePath -- pretty much |
| 113 | + # anything could be a valid unix path |
| 114 | + allow_length2_sequence=False, |
| 115 | + ), |
| 116 | + error_message=f'not a dict, length-2-iterable, or space-delimited str', |
113 | 117 | )
|
114 | 118 | # each specification items is either a mapping url->path, just a url, or a
|
115 | 119 | # JSON-encoded url->path mapping. the order is complex-to-simple for the
|
116 | 120 | # first two (to be able to distinguish a mapping from an encoded URL. The
|
117 | 121 | # JSON-encoding is tried last, it want match accidentally)
|
118 |
| - spec_item_constraint = url2path_constraint | ( |
119 |
| - ( |
120 |
| - EnsureJSON() | EnsureURLFilenamePairFromURL() |
121 |
| - ) & url2path_constraint) |
| 122 | + urlonly_item_constraint = WithDescription( |
| 123 | + EnsureURLFilenamePairFromURL() & url2path_constraint, |
| 124 | + error_message='not a URL with a path component ' |
| 125 | + 'from which a filename can be derived', |
| 126 | + ) |
| 127 | + json_item_constraint = WithDescription( |
| 128 | + EnsureJSON() & url2path_constraint, |
| 129 | + error_message='not a JSON-encoded str with an object or length-2-array', |
| 130 | + ) |
| 131 | + any_item_constraint = WithDescription( |
| 132 | + AnyOf( |
| 133 | + # TODO explain |
| 134 | + url2path_constraint, |
| 135 | + urlonly_item_constraint, |
| 136 | + json_item_constraint, |
| 137 | + ), |
| 138 | + error_message='not a single item\n{__itemized_causes__}', |
| 139 | + ) |
122 | 140 |
|
123 | 141 | # we support reading specification items (matching any format defined
|
124 | 142 | # above) as
|
125 | 143 | # - a single item
|
126 | 144 | # - as a list of items
|
127 | 145 | # - a list given in a file, or via stdin (or any file-like in Python)
|
128 |
| - spec_constraint = AnyOf( |
129 |
| - spec_item_constraint, |
130 |
| - EnsureListOf(spec_item_constraint), |
131 |
| - EnsureGeneratorFromFileLike( |
132 |
| - spec_item_constraint, |
133 |
| - exc_mode='yield', |
| 146 | + spec_constraint = WithDescription( |
| 147 | + AnyOf( |
| 148 | + any_item_constraint, |
| 149 | + WithDescription( |
| 150 | + EnsureListOf(any_item_constraint), |
| 151 | + error_message='not a list of any such item', |
| 152 | + ), |
| 153 | + WithDescription( |
| 154 | + EnsureGeneratorFromFileLike( |
| 155 | + any_item_constraint, |
| 156 | + exc_mode='yield', |
| 157 | + ), |
| 158 | + error_message="not a path to a file with one such item per-line, " |
| 159 | + "nor '-' to read any such item from STDIN", |
| 160 | + ), |
134 | 161 | ),
|
| 162 | + error_message="does not provide URL->(PATH|-) mapping(s)\n{__itemized_causes__}" |
135 | 163 | )
|
136 | 164 |
|
137 | 165 | force_choices = EnsureChoice('overwrite-existing')
|
|
0 commit comments