<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
#
# @Author: oesteban
# @Date:   2016-06-03 09:35:13
from __future__ import print_function, division, absolute_import, unicode_literals
from os import getcwd
import os.path as op
import re
import simplejson as json
from io import open
from builtins import bytes, str
from nipype import logging
from nipype.interfaces.base import (traits, isdefined, TraitedSpec, DynamicTraitedSpec,
                                    BaseInterfaceInputSpec, File, Undefined)
from mriqc.interfaces.base import MRIQCBaseInterface
from mriqc.utils.misc import BIDS_COMP, BIDS_EXPR

IFLOGGER = logging.getLogger('interface')

class ReadSidecarJSONInputSpec(BaseInterfaceInputSpec):
    in_file = File(exists=True, mandatory=True, desc='the input nifti file')
    fields = traits.List(traits.Str, desc='get only certain fields')

class ReadSidecarJSONOutputSpec(TraitedSpec):
    subject_id = traits.Str()
    session_id = traits.Str()
    task_id = traits.Str()
    acq_id = traits.Str()
    rec_id = traits.Str()
    run_id = traits.Str()
    out_dict = traits.Dict()

class ReadSidecarJSON(MRIQCBaseInterface):
    """
    An utility to find and read JSON sidecar files of a BIDS tree
    """
    expr = re.compile(BIDS_EXPR)
    input_spec = ReadSidecarJSONInputSpec
    output_spec = ReadSidecarJSONOutputSpec

    def _run_interface(self, runtime):
        metadata = get_metadata_for_nifti(self.inputs.in_file)
        output_keys = [key for key in list(self.output_spec().get().keys()) if key.endswith('_id')]
        outputs = self.expr.search(op.basename(self.inputs.in_file)).groupdict()

        for key in output_keys:
            id_value = outputs.get(key)
            if id_value is not None:
                self._results[key] = outputs.get(key)

        if isdefined(self.inputs.fields) and self.inputs.fields:
            for fname in self.inputs.fields:
                self._results[fname] = metadata[fname]
        else:
            self._results['out_dict'] = metadata

        return runtime


class IQMFileSinkInputSpec(DynamicTraitedSpec, BaseInterfaceInputSpec):
    subject_id = traits.Str(mandatory=True, desc='the subject id')
    modality = traits.Str(mandatory=True, desc='the qc type')
    session_id = traits.Either(None, traits.Str, usedefault=True)
    task_id = traits.Either(None, traits.Str, usedefault=True)
    acq_id = traits.Either(None, traits.Str, usedefault=True)
    rec_id = traits.Either(None, traits.Str, usedefault=True)
    run_id = traits.Either(None, traits.Str, usedefault=True)

    root = traits.Dict(desc='output root dictionary')
    out_dir = File(desc='the output directory')
    _outputs = traits.Dict(value={}, usedefault=True)

    def __setattr__(self, key, value):
        if key not in self.copyable_trait_names():
            if not isdefined(value):
                super(IQMFileSinkInputSpec, self).__setattr__(key, value)
            self._outputs[key] = value
        else:
            if key in self._outputs:
                self._outputs[key] = value
            super(IQMFileSinkInputSpec, self).__setattr__(key, value)


class IQMFileSinkOutputSpec(TraitedSpec):
    out_file = File(desc='the output JSON file containing the IQMs')

class IQMFileSink(MRIQCBaseInterface):
    input_spec = IQMFileSinkInputSpec
    output_spec = IQMFileSinkOutputSpec
    expr = re.compile('^root[0-9]+$')

    def __init__(self, fields=None, force_run=True, **inputs):
        super(IQMFileSink, self).__init__(**inputs)

        if fields is None:
            fields = []

        self._out_dict = {}

        # Initialize fields
        fields = list(set(fields) - set(self.inputs.copyable_trait_names()))
        self._input_names = fields
        undefined_traits = {key: self._add_field(key) for key in fields}
        self.inputs.trait_set(trait_change_notify=False, **undefined_traits)

        if force_run:
            self._always_run = True

    def _add_field(self, name, value=Undefined):
        self.inputs.add_trait(name, traits.Any)
        self.inputs._outputs[name] = value
        return value

    def _gen_outfile(self):
        out_dir = getcwd()
        if isdefined(self.inputs.out_dir):
            out_dir = self.inputs.out_dir

        fname_comps = []
        for comp, cpre in list(BIDS_COMP.items()):
            comp_val = None
            if isdefined(getattr(self.inputs, comp)):
                comp_val = getattr(self.inputs, comp)
                if comp_val == "None":
                    comp_val = None

            comp_fmt = '{}-{}'.format
            if comp_val is not None:
                if isinstance(comp_val, (bytes, str)) and comp_val.startswith(cpre + '-'):
                    comp_val = comp_val.split('-', 1)[-1]
                fname_comps.append(comp_fmt(cpre, comp_val))

        fname_comps.append('%s.json' % self.inputs.modality)
        self._results['out_file'] = op.join(out_dir, '_'.join(fname_comps))
        return self._results['out_file']

    def _run_interface(self, runtime):
        out_file = self._gen_outfile()

        if isdefined(self.inputs.root):
            self._out_dict = self.inputs.root

        root_adds = []
        for key, val in list(self.inputs._outputs.items()):
            if not isdefined(val) or key == 'trait_added':
                continue

            if not self.expr.match(key) is None:
                root_adds.append(key)
                continue

            key, val = _process_name(key, val)
            self._out_dict[key] = val

        for root_key in root_adds:
            val = self.inputs._outputs.get(root_key, None)
            if isinstance(val, dict):
                self._out_dict.update(val)
            else:
                IFLOGGER.warn(
                    'Output "%s" is not a dictionary (value="%s"), '
                    'discarding output.', root_key, str(val))

        id_dict = {}
        for comp in list(BIDS_COMP.keys()):
            comp_val = getattr(self.inputs, comp, None)
            if isdefined(comp_val) and comp_val is not None:
                id_dict[comp] = comp_val

        # Predict QA from IQMs and add to metadata
        if self.inputs.modality == 'T1w':
            from pkg_resources import resource_filename as pkgrf
            import numpy as np
            from mriqc.classifier.cv import CVHelper

            cvhelper = CVHelper(load_clf=pkgrf('mriqc', 'data/rfc-nzs-full-1.0.pklz'),
                                n_jobs=1)

            features = tuple([self._out_dict.pop(key, None)
                              for key in cvhelper.ftnames])
            id_dict['mriqc_pred'] = cvhelper.predict(np.array([features]))[0]
<commit_msg>fix prediction addition to jiqms<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
#
# @Author: oesteban
# @Date:   2016-06-03 09:35:13
from __future__ import print_function, division, absolute_import, unicode_literals
from os import getcwd
import os.path as op
import re
import simplejson as json
from io import open
from builtins import bytes, str
from nipype import logging
from nipype.interfaces.base import (traits, isdefined, TraitedSpec, DynamicTraitedSpec,
                                    BaseInterfaceInputSpec, File, Undefined)
from mriqc.interfaces.base import MRIQCBaseInterface
from mriqc.utils.misc import BIDS_COMP, BIDS_EXPR

IFLOGGER = logging.getLogger('interface')

class ReadSidecarJSONInputSpec(BaseInterfaceInputSpec):
    in_file = File(exists=True, mandatory=True, desc='the input nifti file')
    fields = traits.List(traits.Str, desc='get only certain fields')

class ReadSidecarJSONOutputSpec(TraitedSpec):
    subject_id = traits.Str()
    session_id = traits.Str()
    task_id = traits.Str()
    acq_id = traits.Str()
    rec_id = traits.Str()
    run_id = traits.Str()
    out_dict = traits.Dict()

class ReadSidecarJSON(MRIQCBaseInterface):
    """
    An utility to find and read JSON sidecar files of a BIDS tree
    """
    expr = re.compile(BIDS_EXPR)
    input_spec = ReadSidecarJSONInputSpec
    output_spec = ReadSidecarJSONOutputSpec

    def _run_interface(self, runtime):
        metadata = get_metadata_for_nifti(self.inputs.in_file)
        output_keys = [key for key in list(self.output_spec().get().keys()) if key.endswith('_id')]
        outputs = self.expr.search(op.basename(self.inputs.in_file)).groupdict()

        for key in output_keys:
            id_value = outputs.get(key)
            if id_value is not None:
                self._results[key] = outputs.get(key)

        if isdefined(self.inputs.fields) and self.inputs.fields:
            for fname in self.inputs.fields:
                self._results[fname] = metadata[fname]
        else:
            self._results['out_dict'] = metadata

        return runtime


class IQMFileSinkInputSpec(DynamicTraitedSpec, BaseInterfaceInputSpec):
    subject_id = traits.Str(mandatory=True, desc='the subject id')
    modality = traits.Str(mandatory=True, desc='the qc type')
    session_id = traits.Either(None, traits.Str, usedefault=True)
    task_id = traits.Either(None, traits.Str, usedefault=True)
    acq_id = traits.Either(None, traits.Str, usedefault=True)
    rec_id = traits.Either(None, traits.Str, usedefault=True)
    run_id = traits.Either(None, traits.Str, usedefault=True)

    root = traits.Dict(desc='output root dictionary')
    out_dir = File(desc='the output directory')
    _outputs = traits.Dict(value={}, usedefault=True)

    def __setattr__(self, key, value):
        if key not in self.copyable_trait_names():
            if not isdefined(value):
                super(IQMFileSinkInputSpec, self).__setattr__(key, value)
            self._outputs[key] = value
        else:
            if key in self._outputs:
                self._outputs[key] = value
            super(IQMFileSinkInputSpec, self).__setattr__(key, value)


class IQMFileSinkOutputSpec(TraitedSpec):
    out_file = File(desc='the output JSON file containing the IQMs')

class IQMFileSink(MRIQCBaseInterface):
    input_spec = IQMFileSinkInputSpec
    output_spec = IQMFileSinkOutputSpec
    expr = re.compile('^root[0-9]+$')

    def __init__(self, fields=None, force_run=True, **inputs):
        super(IQMFileSink, self).__init__(**inputs)

        if fields is None:
            fields = []

        self._out_dict = {}

        # Initialize fields
        fields = list(set(fields) - set(self.inputs.copyable_trait_names()))
        self._input_names = fields
        undefined_traits = {key: self._add_field(key) for key in fields}
        self.inputs.trait_set(trait_change_notify=False, **undefined_traits)

        if force_run:
            self._always_run = True

    def _add_field(self, name, value=Undefined):
        self.inputs.add_trait(name, traits.Any)
        self.inputs._outputs[name] = value
        return value

    def _gen_outfile(self):
        out_dir = getcwd()
        if isdefined(self.inputs.out_dir):
            out_dir = self.inputs.out_dir

        fname_comps = []
        for comp, cpre in list(BIDS_COMP.items()):
            comp_val = None
            if isdefined(getattr(self.inputs, comp)):
                comp_val = getattr(self.inputs, comp)
                if comp_val == "None":
                    comp_val = None

            comp_fmt = '{}-{}'.format
            if comp_val is not None:
                if isinstance(comp_val, (bytes, str)) and comp_val.startswith(cpre + '-'):
                    comp_val = comp_val.split('-', 1)[-1]
                fname_comps.append(comp_fmt(cpre, comp_val))

        fname_comps.append('%s.json' % self.inputs.modality)
        self._results['out_file'] = op.join(out_dir, '_'.join(fname_comps))
        return self._results['out_file']

    def _run_interface(self, runtime):
        out_file = self._gen_outfile()

        if isdefined(self.inputs.root):
            self._out_dict = self.inputs.root

        root_adds = []
        for key, val in list(self.inputs._outputs.items()):
            if not isdefined(val) or key == 'trait_added':
                continue

            if not self.expr.match(key) is None:
                root_adds.append(key)
                continue

            key, val = _process_name(key, val)
            self._out_dict[key] = val

        for root_key in root_adds:
            val = self.inputs._outputs.get(root_key, None)
            if isinstance(val, dict):
                self._out_dict.update(val)
            else:
                IFLOGGER.warn(
                    'Output "%s" is not a dictionary (value="%s"), '
                    'discarding output.', root_key, str(val))

        id_dict = {}
        for comp in list(BIDS_COMP.keys()):
            comp_val = getattr(self.inputs, comp, None)
            if isdefined(comp_val) and comp_val is not None:
                id_dict[comp] = comp_val

        # Predict QA from IQMs and add to metadata
        if self.inputs.modality == 'T1w':
            from pkg_resources import resource_filename as pkgrf
            import numpy as np
            from mriqc.classifier.cv import CVHelper

            cvhelper = CVHelper(load_clf=pkgrf('mriqc', 'data/rfc-nzs-full-1.0.pklz'),
                                n_jobs=1)

            features = tuple([self._out_dict.pop(key, None)
                              for key in cvhelper.ftnames])
            id_dict['mriqc_pred'] = int(cvhelper.predict(np.array([features]))[0])

{'fraction_non_alphanumeric': 0.1067193675889328, 'fraction_numerical': 0.004098960620699751, 'mean_word_length': 2.4704089408178818, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '481852', 'n_tokens_mistral': 4335, 'n_tokens_neox': 4168, 'n_words': 948}