@@ -156,55 +156,69 @@ def check_fields_input_spec(self):
156
156
157
157
"""
158
158
fields = attr_fields (self )
159
- names = []
160
- require_to_check = {}
161
- for fld in fields :
162
- mdata = fld .metadata
163
- # checking if the mandatory field is provided
164
- if getattr (self , fld .name ) is attr .NOTHING :
165
- if mdata .get ("mandatory" ):
166
- # checking if the mandatory field is provided elsewhere in the xor list
167
- in_exclusion_list = mdata .get ("xor" ) is not None
168
- alreday_populated = in_exclusion_list and [
169
- getattr (self , el )
170
- for el in mdata ["xor" ]
171
- if (getattr (self , el ) is not attr .NOTHING )
172
- ]
173
- if (
174
- alreday_populated
175
- ): # another input satisfies mandatory attribute via xor condition
176
- continue
159
+
160
+ for field in fields :
161
+ field_is_mandatory = bool (field .metadata .get ("mandatory" ))
162
+ field_is_unset = getattr (self , field .name ) is attr .NOTHING
163
+
164
+ # Collect alternative fields associated with this field.
165
+ alternative_fields = {
166
+ name : getattr (self , name ) is not attr .NOTHING
167
+ for name in field .metadata .get ("xor" , [])
168
+ if name != field .name
169
+ }
170
+
171
+ # Collect required fields associated with this field.
172
+ required_fields = {
173
+ name : getattr (self , name ) is not attr .NOTHING
174
+ for name in field .metadata .get ("requires" , [])
175
+ if name != field .name
176
+ }
177
+
178
+ # Raise error if field is mandatory and unset
179
+ # or no suitable alternative is provided.
180
+ if field_is_unset :
181
+ if field_is_mandatory :
182
+ if alternative_fields :
183
+ if any (alternative_fields .values ()):
184
+ # Alternative fields found, skip other checks.
185
+ continue
186
+ else :
187
+ raise AttributeError (
188
+ f"{ field .name } is mandatory and unset, "
189
+ "but no value provided by "
190
+ f"{ list (alternative_fields .keys ())} ."
191
+ )
177
192
else :
178
193
raise AttributeError (
179
- f"{ fld .name } is mandatory, but no value provided"
194
+ f"{ field .name } is mandatory, but no value provided. "
180
195
)
181
196
else :
197
+ # Field is not set, check the next one.
182
198
continue
183
- names .append (fld .name )
184
199
185
- # checking if fields meet the xor and requires are
186
- if "xor" in mdata :
187
- if [el for el in mdata ["xor" ] if (el in names and el != fld .name )]:
188
- raise AttributeError (
189
- f"{ fld .name } is mutually exclusive with { mdata ['xor' ]} "
190
- )
200
+ # Raise error if multiple alternatives are set.
201
+ if alternative_fields and any (alternative_fields .values ()):
202
+ set_alternative_fields = [
203
+ name for name , is_set in alternative_fields .items () if is_set
204
+ ]
205
+ raise AttributeError (
206
+ f"{ field .name } is mutually exclusive with { set_alternative_fields } "
207
+ )
191
208
192
- if "requires" in mdata :
193
- if [el for el in mdata ["requires" ] if el not in names ]:
194
- # will check after adding all fields to names
195
- require_to_check [fld .name ] = mdata ["requires" ]
209
+ # Raise error if any required field is unset.
210
+ if required_fields and not all (required_fields .values ()):
211
+ unset_required_fields = [
212
+ name for name , is_set in required_fields .items () if not is_set
213
+ ]
214
+ raise AttributeError (f"{ field .name } requires { unset_required_fields } " )
196
215
197
216
if (
198
- fld .type in [File , Directory ]
199
- or "pydra.engine.specs.File" in str (fld .type )
200
- or "pydra.engine.specs.Directory" in str (fld .type )
217
+ field .type in [File , Directory ]
218
+ or "pydra.engine.specs.File" in str (field .type )
219
+ or "pydra.engine.specs.Directory" in str (field .type )
201
220
):
202
- self ._file_check (fld )
203
-
204
- for nm , required in require_to_check .items ():
205
- required_notfound = [el for el in required if el not in names ]
206
- if required_notfound :
207
- raise AttributeError (f"{ nm } requires { required_notfound } " )
221
+ self ._file_check (field )
208
222
209
223
def _file_check (self , field ):
210
224
"""checking if the file exists"""
0 commit comments