@@ -42,26 +42,46 @@ def define_analysis(gear_name, create_inputs, label=None):
4242
4343
4444class FlywheelFileContainer (dict ):
45- def find_file (self , pattern ):
45+ def find_file (self , pattern , ** kwargs ):
4646 '''Find a file in this container with a name that matches pattern.
4747
4848 This will look for a file in this container that matches the supplied
4949 pattern. Matching uses the fnmatch python library, which does Unix
5050 filename pattern matching.
5151
52+ kwargs['default'] - like `next`, when a default is supplied, it will be
53+ returned when there are no matches. When a default is not supplied, an
54+ exception will be thrown.
55+
5256 To find a specific file, you can simply match by name:
5357 > acquisition.find_file('anatomical.nii.gz')
5458
5559 To find a file with an extension, you can use a Unix-style pattern:
5660 > stimulus_onsets.find_file('*.txt')
61+
62+ When looking for a file that might be missing, supply a default value:
63+ > partial_set_of_files.find_file('*.txt', default=None)
5764 '''
58- # TODO make sure this throws for missing or multiple files.
65+ has_default = 'default' in kwargs
5966 is_analysis = 'job' in self and 'state' in self
6067
6168 # XXX if is_analysis then we should require the file to be an output??
62- f = next (
69+ matches = [
6370 f for f in self ['files' ]
64- if fnmatch (f ['name' ], pattern ))
71+ if fnmatch (f ['name' ], pattern )]
72+
73+ assert len (matches ) <= 1 , (
74+ 'Multiple matches found for pattern "{}" in container {}. Patterns should uniquely identify a file.'
75+ .format (pattern , self ['_id' ]))
76+ if not matches :
77+ if has_default :
78+ return kwargs .get ('default' )
79+ else :
80+ raise Exception (
81+ 'Could not find a match for "{}" in container {}.'
82+ .format (pattern , self ['_id' ]))
83+
84+ f = matches [0 ]
6585
6686 return dict (
6787 type = 'analysis' if is_analysis else 'acquisition' ,
0 commit comments