Example #1
0
    def dicom_values(self, tags):
        """
        Returns a dictionary with the DICOM header fields corresponding
        to the given tag names

        Parameters
        ----------
        tags : List[Tuple[str, str]]
            List of DICOM tag values as 2-tuple of strings, e.g.
            [('0080', '0020')]
        repository_login : <repository-login-object>
            A login object for the repository to avoid having to relogin
            for every dicom_header call.

        Returns
        -------
        dct : Dict[Tuple[str, str], str|int|float]
        """
        try:
            if (self._path is None and self._repository is not None and
                    hasattr(self.repository, 'dicom_header')):
                hdr = self.repository.dicom_header(self)
                dct = {t: hdr[t] for t in tags}
            else:
                # Get the DICOM object for the first file in the fileset
                dcm = self.dicom(0)
                dct = {t: dcm[t].value for t in tags}
        except KeyError as e:
            raise ArcanaNameError(
                e.args[0], "{} does not have dicom tag {}".format(
                    self, e.args[0]))
        return dct
Example #2
0
 def session(self, subject_id):
     try:
         return self._sessions[subject_id]
     except KeyError:
         raise ArcanaNameError(
             subject_id, ("{} doesn't have a session named '{}'".format(
                 self, subject_id)))
Example #3
0
    def spec(self, name):
        """
        Returns either the input corresponding to a fileset or field
        field spec or a spec or parameter that has either
        been passed to the study as an input or can be derived.

        Parameters
        ----------
        name : Str | BaseData | Parameter
            An parameter, fileset or field or name of one
        """
        if isinstance(name, (BaseData, Parameter)):
            name = name.name
        try:
            spec = self._inputs[name]
        except KeyError:
            try:
                spec = self._bound_specs[name]
            except KeyError:
                if name in self._data_specs:
                    raise ArcanaMissingDataException(
                        "Acquired (i.e. non-generated) fileset '{}' "
                        "was not supplied when the study '{}' was "
                        "initiated".format(name, self.name))
                else:
                    try:
                        spec = self._param_specs[name]
                    except KeyError:
                        raise ArcanaNameError(
                            name, "'{}' is not a recognised spec name "
                            "for {} studies:\n{}.".format(
                                name, self.__class__.__name__,
                                '\n'.join(sorted(self.spec_names()))))
        return spec
Example #4
0
 def sub_study_spec(cls, name):
     try:
         return cls._sub_study_specs[name]
     except KeyError:
         raise ArcanaNameError(
             name, "'{}' not found in sub-studes ('{}')".format(
                 name, "', '".join(cls._sub_study_specs)))
Example #5
0
 def sub_study(self, name):
     try:
         return self._sub_studies[name]
     except KeyError:
         raise ArcanaNameError(
             name, "'{}' not found in sub-studes ('{}')".format(
                 name, "', '".join(self._sub_studies)))
Example #6
0
 def parameter_spec(cls, name):
     try:
         return cls._param_specs[name]
     except KeyError:
         raise ArcanaNameError(
             name, "No parameter spec named '{}' in {} (available: "
             "'{}')".format(name, cls.__name__,
                            "', '".join(list(cls._param_specs.keys()))))
Example #7
0
 def _get_parameter(self, name):
     try:
         parameter = self._parameters[name]
     except KeyError:
         try:
             parameter = self._param_specs[name]
         except KeyError:
             raise ArcanaNameError(
                 name, "Invalid parameter, '{}', in {} (valid '{}')".format(
                     name, self._param_error_location,
                     "', '".join(self.parameter_spec_names())))
     return parameter
Example #8
0
 def map(self, name):
     try:
         return self._name_map[name]
     except KeyError:
         if name not in self.study_class.spec_names():
             raise ArcanaNameError(
                 name,
                 "'{}' doesn't match any filesets, fields, parameters "
                 "in the study class {} ('{}')".format(
                     name, self.name, self.study_class.__name__,
                     "', '".join(self.study_class.spec_names())))
         return self.apply_prefix(name)
Example #9
0
    def data_spec(cls, name):
        """
        Return the fileset_spec, i.e. the template of the fileset expected to
        be supplied or generated corresponding to the fileset_spec name.

        Parameters
        ----------
        name : Str
            Name of the fileset_spec to return
        """
        if isinstance(name, BaseData):
            name = name.name
        try:
            return cls._data_specs[name]
        except KeyError:
            raise ArcanaNameError(
                name, "No fileset spec named '{}' in {} (available: "
                "'{}')".format(name, cls.__name__,
                               "', '".join(list(cls._data_specs.keys()))))
Example #10
0
 def field(self, name, study=None):
     try:
         return self._fields[(name, study)]
     except KeyError:
         available = [d.name for d in self.fields if d.from_study == study]
         other_studies = [
             d.from_study for d in self.fields if d.name == name
         ]
         if other_studies:
             msg = (
                 ". NB: matching field(s) found for '{}' study(ies)".format(
                     name, other_studies))
         else:
             msg = ''
         raise ArcanaNameError(
             name, ("{} doesn't have a field named '{}' "
                    "(available '{}')".format(
                        self, name,
                        ("for study '{}'" if study is not None else ''),
                        "', '".join(available), other_studies), msg))
Example #11
0
 def visit(self, id):  # @ReservedAssignment
     try:
         return self._visits[id]
     except KeyError:
         raise ArcanaNameError(
             id, ("{} doesn't have a visit named '{}'".format(self, id)))
Example #12
0
 def input(self, name):
     try:
         return self._inputs[name]
     except KeyError:
         raise ArcanaNameError(
             name, "{} doesn't have an input named '{}'".format(self, name))
Example #13
0
 def __init__(self,
              name,
              repository,
              processor,
              inputs,
              environment=None,
              parameters=None,
              subject_ids=None,
              visit_ids=None,
              enforce_inputs=True,
              reprocess=False,
              fill_tree=False):
     try:
         # This works for PY3 as the metaclass inserts it itself if
         # it isn't provided
         metaclass = type(self).__dict__['__metaclass__']
         if not issubclass(metaclass, StudyMetaClass):
             raise KeyError
     except KeyError:
         raise ArcanaUsageError(
             "Need to have StudyMetaClass (or a sub-class) as "
             "the metaclass of all classes derived from Study")
     if isinstance(repository, basestring):
         repository = DirectoryRepository(repository, depth=None)
     if isinstance(processor, basestring):
         processor = LinearProcessor(processor)
     if environment is None:
         environment = StaticEnvironment()
     self._name = name
     self._repository = repository
     self._processor = processor.bind(self)
     self._environment = environment
     self._inputs = {}
     self._subject_ids = subject_ids
     self._visit_ids = visit_ids
     self._tree = self.repository.cached_tree(subject_ids=subject_ids,
                                              visit_ids=visit_ids,
                                              fill=fill_tree)
     if not self.subject_ids:
         raise ArcanaUsageError(
             "No subject IDs provided and destination repository "
             "is empty")
     if not self.visit_ids:
         raise ArcanaUsageError(
             "No visit IDs provided and destination repository "
             "is empty")
     self._reprocess = reprocess
     # For recording which parameters are accessed
     # during pipeline generation so they can be attributed to the
     # pipeline after it is generated (and then saved in the
     # provenance
     self._pipeline_to_generate = None
     self._referenced_parameters = None
     # Set parameters
     if parameters is None:
         parameters = {}
     elif not isinstance(parameters, dict):
         # Convert list of parameters into dictionary
         parameters = {o.name: o for o in parameters}
     self._parameters = {}
     for param_name, param in list(parameters.items()):
         if not isinstance(param, Parameter):
             param = Parameter(param_name, param)
         try:
             param_spec = self._param_specs[param_name]
         except KeyError:
             raise ArcanaNameError(
                 param_name,
                 "Provided parameter '{}' is not present in the "
                 "allowable parameters for {} classes ('{}')".format(
                     param_name,
                     type(self).__name__,
                     "', '".join(self.parameter_spec_names())))
         param_spec.check_valid(param,
                                context='{}(name={})'.format(
                                    type(self).__name__, name))
         self._parameters[param_name] = param
     # Convert inputs to a dictionary if passed in as a list/tuple
     if not isinstance(inputs, dict):
         inputs = {i.name: i for i in inputs}
     # Add each "input fileset" checking to see whether the given
     # fileset_spec name is valid for the study types
     for inpt_name, inpt in list(inputs.items()):
         try:
             spec = self.data_spec(inpt_name)
         except ArcanaNameError:
             raise ArcanaNameError(
                 inpt.name,
                 "Input name '{}' isn't in data specs of {} ('{}')".format(
                     inpt.name, self.__class__.__name__,
                     "', '".join(self._data_specs)))
         else:
             if isinstance(spec, BaseFileset):
                 if isinstance(inpt, BaseField):
                     raise ArcanaUsageError(
                         "Passed field ({}) as input to fileset spec"
                         " {}".format(inpt, spec))
                 if spec.derived:
                     try:
                         # FIXME: should provide requirement manager to
                         # converter_from but it hasn't been implemented yet
                         spec.format.converter_from(inpt.format)
                     except ArcanaNoConverterError as e:
                         raise ArcanaNoConverterError(
                             "{}, which is requried to convert:\n{} "
                             "to\n{}.".format(e, inpt, spec))
                 else:
                     if inpt.format not in spec.valid_formats:
                         raise ArcanaUsageError(
                             "Cannot pass {} as an input to {} as it is "
                             "not in one of the valid formats ('{}')".
                             format(
                                 inpt, spec,
                                 "', '".join(f.name
                                             for f in spec.valid_formats)))
             elif not isinstance(inpt, BaseField):
                 raise ArcanaUsageError(
                     "Passed fileset ({}) as input to field spec {}".format(
                         inpt, spec))
         self._inputs[inpt_name] = inpt.bind(self)
     # "Bind" data specs in the class to the current study object
     # this will allow them to prepend the study name to the name
     # of the fileset
     self._bound_specs = {}
     for spec in self.data_specs():
         if spec.name not in self.input_names:
             if not spec.derived and spec.default is None:
                 # Emit a warning if an acquired fileset has not been
                 # provided for an "acquired fileset"
                 msg = (" acquired fileset '{}' was not given as"
                        " an input of {}.".format(spec.name, self))
                 if spec.optional:
                     logger.info('Optional' + msg)
                 else:
                     if enforce_inputs:
                         raise ArcanaMissingInputError(
                             'Non-optional' + msg + " Pipelines "
                             "depending on this fileset will not "
                             "run")
             else:
                 self._bound_specs[spec.name] = spec.bind(self)
Example #14
0
 def __init__(self,
              name,
              repository,
              processor,
              inputs,
              parameters=None,
              **kwargs):
     try:
         # This works for PY3 as the metaclass inserts it itself if
         # it isn't provided
         metaclass = type(self).__dict__['__metaclass__']
         if not issubclass(metaclass, MultiStudyMetaClass):
             raise KeyError
     except KeyError:
         raise ArcanaUsageError(
             "Need to set MultiStudyMetaClass (or sub-class) as "
             "the metaclass of all classes derived from "
             "MultiStudy")
     super(MultiStudy, self).__init__(name,
                                      repository,
                                      processor,
                                      inputs,
                                      parameters=parameters,
                                      **kwargs)
     self._sub_studies = {}
     for sub_study_spec in self.sub_study_specs():
         sub_study_cls = sub_study_spec.study_class
         # Map inputs, data_specs to the sub_study
         mapped_inputs = {}
         for data_name in sub_study_cls.data_spec_names():
             mapped_name = sub_study_spec.map(data_name)
             if mapped_name in self.input_names:
                 mapped_inputs[data_name] = self.input(mapped_name)
             else:
                 try:
                     inpt = self.spec(mapped_name)
                 except ArcanaMissingDataException:
                     pass
                 else:
                     if inpt.derived:
                         mapped_inputs[data_name] = inpt
         # Map parameters to the sub_study
         mapped_parameters = {}
         for param_name in sub_study_cls.parameter_spec_names():
             mapped_name = sub_study_spec.map(param_name)
             parameter = self._get_parameter(mapped_name)
             mapped_parameters[param_name] = parameter
         # Create sub-study
         sub_study = sub_study_spec.study_class(
             name + '_' + sub_study_spec.name,
             repository,
             processor,
             mapped_inputs,
             parameters=mapped_parameters,
             enforce_inputs=False)
         # Append to dictionary of sub_studies
         if sub_study_spec.name in self._sub_studies:
             raise ArcanaNameError(
                 sub_study_spec.name,
                 "Duplicate sub-study names '{}'".format(
                     sub_study_spec.name))
         self._sub_studies[sub_study_spec.name] = sub_study