示例#1
0
def _worker_initialize():
    """
    Initializer function for multiprocessing workers.
    
    This makes sure plugins are loaded and paths to local files are set
    """
    set_local_file_path()
    get_plugins()
    def resamp(self, qpdata):
        """
        Resample a map according to resampling options
        """
        resamp_options = dict(self.options.get("resampling", {}))
        if resamp_options:
            resamp_processes = get_plugins("processes", "ResampleProcess")
            if len(resamp_processes) != 1:
                raise QpException("Can't identify Resampling process")

            ivm = ImageVolumeManagement()
            ivm.add(qpdata)
            process = resamp_processes[0](ivm)
            resamp_options.update({
                "data": qpdata.name,
                "output-name": "output_res"
            })
            process.execute(resamp_options)
            while process.status == Process.RUNNING:
                time.sleep(1)

            if process.status == Process.FAILED:
                raise process.exception

            # FIXME hack
            process._complete()
            return ivm.data["output_res"]
        else:
            return qpdata
    def structure_maps(self):
        processes = get_plugins("processes", "FastProcess")
        if len(processes) != 1:
            raise QpException("Can't identify Fast process")

        struc = self.options.get("struc", None)
        if struc not in self._ivm.data:
            raise QpException("Structural image not loaded: %s" % struc)

        qpdata = self._ivm.data[struc]
        ivm = ImageVolumeManagement()
        ivm.add(qpdata)
        process = processes[0](ivm)
        fast_options = {
            "data": qpdata.name,
            "class": 3,
            "type": self.options["type"],
            "output-pve": True,
            "output-pveseg": False,
        }
        process.execute(fast_options)
        while process.status == Process.RUNNING:
            time.sleep(1)

        if process.status == Process.FAILED:
            raise process.exception

        # FIXME hack
        process._complete()

        return {
            "gm": ivm.data["%s_pve_1" % qpdata.name],
            "wm": ivm.data["%s_pve_2" % qpdata.name],
            "csf": ivm.data["%s_pve_0" % qpdata.name],
        }
    def _smooth_pv(self, qpdata, sigma):
        """
        Do Gaussian smoothing on a partial volume map

        Typically when the map is a discrete ROI and we want to smoothly blend it into
        the other tissue PV maps

        :param qpdata: PV map
        :param sigma: Gaussian kernel std.dev in mm
        :return: Smoothed PV map as Numpy array
        """
        smooth_processes = get_plugins("processes", "SmoothingProcess")
        if len(smooth_processes) != 1:
            raise QpException("Can't identify smoothing process")

        ivm = ImageVolumeManagement()
        ivm.add(qpdata)
        process = smooth_processes[0](ivm)
        smooth_options = {
            "data": qpdata.name,
            "sigma": sigma,
            "output-name": "output_smooth",
        }
        process.execute(smooth_options)
        while process.status == Process.RUNNING:
            time.sleep(1)

        if process.status == Process.FAILED:
            raise process.exception

        # FIXME hack
        process._complete()
        return ivm.data["output_smooth"].raw()
示例#5
0
    def init_ui(self):
        vbox = QtGui.QVBoxLayout()
        self.setLayout(vbox)

        try:
            proc = get_plugins("processes", "FabberProcess")[0]
        except:
            proc = None

        if proc is None:
            vbox.addWidget(
                QtGui.QLabel(
                    "Fabber core library not found.\n\n You must install Fabber to use this widget"
                ))
            return

        title = TitleWidget(self,
                            help="fabber-dsc",
                            subtitle="Bayesian modelling for DSC-MRI %s" %
                            __version__)
        vbox.addWidget(title)

        cite = Citation(FAB_CITE_TITLE, FAB_CITE_AUTHOR, FAB_CITE_JOURNAL)
        vbox.addWidget(cite)

        tabs = QtGui.QTabWidget()
        vbox.addWidget(tabs)
        self.dsc_widget = DscOptionsWidget(self.ivm)
        tabs.addTab(self.dsc_widget, "DSC Options")
        self.aif_widget = AifWidget(self.ivm)
        tabs.addTab(self.aif_widget, "AIF")
        vbox.addWidget(tabs)

        vbox.addWidget(RunWidget(self, save_option=True))
        vbox.addStretch(1)
示例#6
0
def _run_reg(worker_id, queue, method_name, mode, reg_data, ref_data, options):
    """
    Generic registration function for asynchronous process
    """
    try:
        set_local_file_path()
        method = get_reg_method(method_name)
        if method is None:
            raise QpException("Unknown registration method: %s (known: %s)" %
                              (method_name, str(get_plugins("reg-methods"))))

        if not reg_data:
            raise QpException("No registration data")
        elif mode == "moco":
            return _reg_moco(worker_id, method, reg_data, ref_data, options,
                             queue)
        elif reg_data[0].ndim == 3:
            return _reg_3d(worker_id, method, reg_data, ref_data, options,
                           queue)
        else:
            return _reg_4d(worker_id, method, reg_data, ref_data, options,
                           queue)
    except:
        traceback.print_exc()
        return worker_id, False, sys.exc_info()[1]
示例#7
0
def qp_oxasl(worker_id, queue, fsldir, fsldevdir, asldata, options):
    """
    Worker function for asynchronous oxasl run

    Note that images are passed as QpData because it's pickleable
    but need to be converted to fsl.data.image.Image
    """
    try:
        from oxasl import Workspace
        from oxasl.oxford_asl import oxasl
        options["fabber_dirs"] = get_plugins("fabber-dirs")

        if "FSLOUTPUTTYPE" not in os.environ:
            os.environ["FSLOUTPUTTYPE"] = "NIFTI_GZ"
        if fsldir:
            os.environ["FSLDIR"] = fsldir
        if fsldevdir:
            os.environ["FSLDEVDIR"] = fsldevdir

        for key, value in options.items():
            if isinstance(value, QpData):
                options[key] = qpdata_to_fslimage(value)
        options["asldata"], _ = qpdata_to_aslimage(asldata)

        output_monitor = OutputStreamMonitor(queue)
        wsp = Workspace(log=output_monitor, **options)
        oxasl(wsp)

        return worker_id, True, {}
    except:
        traceback.print_exc()
        return worker_id, False, sys.exc_info()[1]
示例#8
0
 def api(model_group=None):
     """
     Return a Fabber API object
     """
     from fabber import Fabber
     search_dirs = get_plugins(key="fabber-dirs")
     return Fabber(*search_dirs)
示例#9
0
    def init_ui(self):
        vbox = QtGui.QVBoxLayout()
        self.setLayout(vbox)

        try:
            self.fabber_process = get_plugins("processes", "FabberProcess")[0]
        except:
            self.fabber_process = None

        if self.fabber_process is None:
            vbox.addWidget(
                QtGui.QLabel(
                    "Fabber core library not found.\n\n You must install Fabber to use this widget"
                ))
            return

        title = TitleWidget(
            self,
            help="cest",
            subtitle=
            "Bayesian Modelling for Chemical Exchange Saturation Transfer MRI %s"
            % __version__)
        vbox.addWidget(title)

        cite = Citation(CEST_CITE_TITLE, CEST_CITE_AUTHOR, CEST_CITE_JOURNAL)
        vbox.addWidget(cite)

        self.tabs = QtGui.QTabWidget()
        self.seqtab = SequenceOptions(self.ivm)
        self.tabs.addTab(self.seqtab, "Sequence")

        self.pooltab = PoolOptions(self.ivm)
        self.tabs.addTab(self.pooltab, "Pools")

        self.analysistab = AnalysisOptions(self.ivm)
        self.tabs.addTab(self.analysistab, "Analysis")

        self.pooltab.sig_pools_changed.connect(self.analysistab.set_pools)
        self.seqtab.sig_b0_changed.connect(self.pooltab.set_b0)
        vbox.addWidget(self.tabs)

        run_tabs = QtGui.QTabWidget()
        run_box = RunBox(self._get_process_model,
                         self._options,
                         title="Run model-based analysis",
                         save_option=True)
        run_tabs.addTab(run_box, "Model based analysis")
        run_box = RunBox(self._get_process_lda,
                         self._options_lda,
                         title="Run Lorentzian Difference analysis",
                         save_option=True)
        run_tabs.addTab(run_box, "Lorentzian Difference analysis")
        vbox.addWidget(run_tabs)

        vbox.addStretch(1)
        self.analysistab.set_pools(self.pooltab.pools)
示例#10
0
    def setUp(self):
        self.qpe, self.error = False, False
        sys.excepthook = self._exc

        self.ivm = ImageVolumeManagement()
        self.ivl = Viewer(self.ivm)

        get_plugins()
        wclass = self.widget_class()
        if wclass is not None:
            self.w = wclass(ivm=self.ivm, ivl=self.ivl)
            self.w.init_ui()
            self.w.activate()
            self.w.show()
        else:
            raise unittest.SkipTest("Plugin not found")

        from . import create_test_data
        create_test_data(self)
示例#11
0
 def __init__(self, **kwargs):
     super(RegWidget, self).__init__(name="Registration", icon="reg", 
                                     desc="Registration and Motion Correction", 
                                     group="Registration", **kwargs)
     self.reg_methods = []
     for method in get_plugins("reg-methods"):
         try:
             self.reg_methods.append(method(self.ivm))
         except:
             traceback.print_exc()
             self.warn("Failed to create registration method: %s", method)
示例#12
0
def get_reg_method(method_name):
    """
    Get a named registration method (case insensitive)
    """
    methods = get_plugins("reg-methods")
    LOG.debug("Known methods: %s", str(methods))
    for method_class in methods:
        method = method_class(None)
        if method.name.lower() == method_name.lower():
            return method
    return None
示例#13
0
 def __init__(self, **kwargs):
     super(ApplyTransform, self).__init__(name="Apply Transform", icon="reg", 
                                          desc="Apply previously calculated transformations", 
                                          group="Registration", **kwargs)
     self.reg_methods = []
     for method in get_plugins("reg-methods"):
         try:
             self.reg_methods.append(method(self.ivm))
         except:
             traceback.print_exc()
             self.warn("Failed to create registration method: %s", method)
示例#14
0
    def init_ui(self):
        vbox = QtGui.QVBoxLayout()
        self.setLayout(vbox)

        title = TitleWidget(
            self,
            help="asl",
            subtitle="Data processing for Arterial Spin Labelling MRI")
        vbox.addWidget(title)

        cite = Citation(FAB_CITE_TITLE, FAB_CITE_AUTHOR, FAB_CITE_JOURNAL)
        vbox.addWidget(cite)

        self.tabs = QtGui.QTabWidget()
        vbox.addWidget(self.tabs)

        self.asldata = AslImageWidget(self.ivm, parent=self)
        self.asldata.sig_changed.connect(self._data_changed)
        self.tabs.addTab(self.asldata, "ASL data")

        self.preproc = PreprocOptions(self.ivm)
        self.preproc.sig_enable_tab.connect(self._enable_tab)
        self.tabs.addTab(self.preproc, "Corrections")

        # Only add these if appropriate
        self._optional_tabs = {
            "veasl": VeaslOptions(self.ivm, self.asldata),
            "enable": EnableOptions(self.ivm),
            "deblur": DeblurOptions(),
        }

        self.structural = StructuralData(self.ivm)
        self.tabs.addTab(self.structural, "Structural data")

        self.calibration = CalibrationOptions(self.ivm)
        self.tabs.addTab(self.calibration, "Calibration")

        self.analysis = AnalysisOptions(self.ivm)
        self.analysis.optbox.option("wp").sig_changed.connect(self._wp_changed)
        self.tabs.addTab(self.analysis, "Analysis")

        self.output = OutputOptions()
        self.tabs.addTab(self.output, "Output")

        runbox = RunWidget(self, title="Run processing", save_option=True)
        runbox.sig_postrun.connect(self._postrun)
        vbox.addWidget(runbox)
        vbox.addStretch(1)

        fsldir_qwidgets = get_plugins("qwidgets", "FslDirWidget")
        if len(fsldir_qwidgets) > 0:
            fsldir = fsldir_qwidgets[0]()
            vbox.addWidget(fsldir)
示例#15
0
def run_tests(test_filter=None):
    """
    Run all unit tests defined by packages and plugins

    :param test_filter: Specifies name of test set to be run, None=run all
    """
    suite = unittest.TestSuite()

    for test in class_tests:
        if test_filter is None or test.__name__.lower().startswith(test_filter.lower()):
            suite.addTests(unittest.defaultTestLoader.loadTestsFromTestCase(test))

    tests = get_plugins("widget-tests")
    for test in tests:
        if test_filter is None or test.__name__.lower().startswith(test_filter.lower()):
            suite.addTests(unittest.defaultTestLoader.loadTestsFromTestCase(test))

    tests = get_plugins("process-tests")
    for test in tests:
        if test_filter is None or test.__name__.lower().startswith(test_filter.lower()):
            suite.addTests(unittest.defaultTestLoader.loadTestsFromTestCase(test))
   
    unittest.TextTestRunner(verbosity=2).run(suite)
示例#16
0
    def __init__(self, ivm, **kwargs):
        try:
            self.fabber = get_plugins("processes",
                                      class_name="FabberProcess")[0](ivm)
            self.fabber.sig_finished.connect(self._fabber_finished)
            self.fabber.sig_progress.connect(self._fabber_progress)
        except Exception as exc:
            self.warn(str(exc))
            raise QpException(
                "Fabber core library not found.\n\n You must install Fabber to use this widget"
            )

        self.steps = []
        self.step_num = 0
        super(BasilProcess, self).__init__(ivm, **kwargs)
示例#17
0
    def __init__(self, ivm):
        FabberDataModel.__init__(self, ivm, "Dynamic Contrast-Enhanced MRI")
        
        from fabber import Fabber
        search_dirs = get_plugins(key="fabber-dirs")
        self._fab = Fabber(*search_dirs)

        self.known_params = [
            Parameter("sig0", "Signal offset", default=100.0),
            Parameter("fp", "Flow, Fp", default=0.5, units="min^-1"),
            Parameter("ps", "Permeability-surface area, PS", default=0.5, units="min^-1"),
            Parameter("ktrans", "Transfer coefficient, Ktrans", default=0.5, units="min^-1"),
            Parameter("ve", "Extracellular volume fraction Ve", default=0.2),
            Parameter("vp", "Vascular plasma volume fraction Vp", default=0.05),
            Parameter("t10", "T1", default=1.0, units="s"),
        ]
示例#18
0
    from PySide import QtGui, QtCore, QtGui as QtWidgets
except ImportError:
    from PySide2 import QtGui, QtCore, QtWidgets

from quantiphyse.gui.widgets import Citation
from quantiphyse.gui.options import OptionBox, DataOption, ChoiceOption
from quantiphyse.utils import get_plugins
from quantiphyse.utils.exceptions import QpException

from .process import qpdata_to_fslimage, fslimage_to_qpdata

CITE_TITLE = "Non-linear registration, aka spatial normalisation"
CITE_AUTHOR = "Andersson JLR, Jenkinson M, Smith S"
CITE_JOURNAL = "FMRIB technical report TR07JA2, 2010"

RegMethod = get_plugins("base-classes", class_name="RegMethod")[0]


def _interp(order):
    return {0: "nn", 1: "trilinear", 2: "spline", 3: "spline"}[order]


class FnirtRegMethod(RegMethod):
    """
    FNIRT registration method
    """
    def __init__(self, ivm):
        RegMethod.__init__(self, "fnirt", ivm, display_name="FNIRT")
        self.options_widget = None

    @classmethod
示例#19
0
def get_data_models():
    ret = {}
    for cls in get_plugins("datasim-data-models"):
        ret[cls.NAME] = cls
    return ret
示例#20
0
    def __init__(self, load_data=None, widgets=True):
        super(MainWindow, self).__init__()

        self.ivm = ImageVolumeManagement()
        self.view_options_dlg = ViewOptions(self, self.ivm)
        self.ivl = ImageView(self.ivm, self.view_options_dlg)

        # Load style sheet
        stylesheet = get_local_file("resources/darkorange.stylesheet")
        with open(stylesheet, "r") as stylesheet_file:
            self.setStyleSheet(stylesheet_file.read())

        # Default dir to load files from is the user's home dir
        self.default_directory = os.path.expanduser("~")

        # Widgets
        self.widget_groups = {}
        self.current_widget = None

        # Main layout - image view to left, tabs to right
        main_widget = QtGui.QWidget()
        hbox = QtGui.QHBoxLayout()
        splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
        splitter.addWidget(self.ivl)
        splitter.setStretchFactor(0, 4)
        hbox.addWidget(splitter)
        main_widget.setLayout(hbox)
        self.setCentralWidget(main_widget)

        if widgets:
            default_size = (1000, 700)
            widgets = get_plugins("widgets")
            for wclass in widgets:
                w = wclass(ivm=self.ivm,
                           ivl=self.ivl,
                           opts=self.view_options_dlg)
                if w.group not in self.widget_groups:
                    self.widget_groups[w.group] = []
                self.widget_groups[w.group].append(w)

            for _, widgets in self.widget_groups.items():
                widgets.sort(key=lambda x: x.position)

            self._init_tabs()
            splitter.addWidget(self.tab_widget)
            splitter.setStretchFactor(1, 1)
        else:
            default_size = (700, 700)

        self.init_menu()

        # General properties of main window
        self.setWindowTitle("Quantiphyse %s" % get_version())
        self.setWindowIcon(QtGui.QIcon(get_icon("main_icon.png")))
        self.resize(*default_size)
        self.setUnifiedTitleAndToolBarOnMac(True)
        self.setAcceptDrops(True)
        self.show()

        # Load any files from the command line
        if load_data:
            for fname in load_data:
                self.load_data(fname=fname)
示例#21
0
    def init_ui(self):
        vbox = QtGui.QVBoxLayout()
        self.setLayout(vbox)

        try:
            self.FabberProcess = get_plugins("processes", "FabberProcess")[0]
        except IndexError:
            self.FabberProcess = None

        if self.FabberProcess is None:
            vbox.addWidget(
                QtGui.QLabel(
                    "Fabber core library not found.\n\n You must install Fabber to use this widget"
                ))
            return

        title = TitleWidget(
            self,
            help="fabber-dsc",
            subtitle="DSC modelling using the Fabber process %s" % __version__)
        vbox.addWidget(title)

        cite = Citation(FAB_CITE_TITLE, FAB_CITE_AUTHOR, FAB_CITE_JOURNAL)
        vbox.addWidget(cite)

        self.input = OptionBox("Input data")
        self.input.add("DCE data",
                       DataOption(self.ivm, include_3d=False, include_4d=True),
                       key="data")
        self.input.add("ROI",
                       DataOption(self.ivm, data=False, rois=True),
                       key="roi",
                       checked=True)
        self.input.add("T1 map",
                       DataOption(self.ivm, include_3d=True, include_4d=False),
                       key="t1",
                       checked=True)
        self.input.option("t1").sig_changed.connect(self._t1_map_changed)
        vbox.addWidget(self.input)

        self.acquisition = OptionBox("Acquisition")
        self.acquisition.add("Contrast agent R1 relaxivity (l/mmol s)",
                             NumericOption(minval=0, maxval=10, default=3.7),
                             key="r1")
        self.acquisition.add("Flip angle (\N{DEGREE SIGN})",
                             NumericOption(minval=0, maxval=90, default=12),
                             key="fa")
        self.acquisition.add("TR (ms)",
                             NumericOption(minval=0, maxval=10, default=4.108),
                             key="tr")
        self.acquisition.add("Time between volumes (s)",
                             NumericOption(minval=0, maxval=30, default=12),
                             key="delt")
        vbox.addWidget(self.acquisition)

        self.model = OptionBox("Model options")
        self.model.add(
            "Model",
            ChoiceOption([
                "Standard Tofts model", "Extended Tofts model (ETM)",
                "2 Compartment exchange model",
                "Compartmental Tissue Update (CTU) model",
                "Adiabatic Approximation to Tissue Homogeneity (AATH) Model"
            ], ["dce_tofts", "dce_ETM", "dce_2CXM", "dce_CTU", "dce_AATH"]),
            key="model")
        self.model.add(
            "AIF",
            ChoiceOption([
                "Population (Orton 2008)", "Population (Parker)",
                "Measured DCE signal", "Measured concentration curve"
            ], ["orton", "parker", "signal", "conc"]),
            key="aif")
        self.model.add("Bolus injection time (s)",
                       NumericOption(minval=0, maxval=60, default=30),
                       key="tinj")
        self.model.add("AIF data values",
                       NumberListOption([
                           0,
                       ]),
                       key="aif-data")
        self.model.add("T1 (s)",
                       NumericOption(minval=0.0, maxval=5.0, default=1.0),
                       key="t10")
        self.model.add("Allow T1 to vary",
                       BoolOption(default=False),
                       key="infer-t10")
        self.model.add("Bolus arrival time (s)",
                       NumericOption(minval=0, maxval=2.0, default=0),
                       key="delay")
        self.model.add("Allow bolus arrival time to vary",
                       BoolOption(default=False),
                       key="infer-delay")
        self.model.add("Infer kep rather than ve",
                       BoolOption(default=False),
                       key="infer-kep")
        self.model.add("Infer flow", BoolOption(default=True), key="infer-fp")
        self.model.add("Infer permeability-surface area",
                       BoolOption(default=False),
                       key="infer-ps")
        self.model.add("Spatial regularization",
                       BoolOption(default=False),
                       key="spatial")
        self.model.option("model").sig_changed.connect(self._model_changed)
        self.model.option("aif").sig_changed.connect(self._aif_changed)
        vbox.addWidget(self.model)

        # Run button and progress
        vbox.addWidget(RunWidget(self, title="Run modelling"))
        vbox.addStretch(1)

        self._aif_changed()
        self._model_changed()
示例#22
0
    def init_ui(self):
        vbox = QtGui.QVBoxLayout()
        self.setLayout(vbox)

        try:
            self.FabberProcess = get_plugins("processes", "FabberProcess")[0]
        except:
            self.FabberProcess = None

        if self.FabberProcess is None:
            vbox.addWidget(
                QtGui.QLabel(
                    "Fabber core library not found.\n\n You must install Fabber to use this widget"
                ))
            return

        title = TitleWidget(
            self,
            help="fabber-t1",
            subtitle="T1 mapping from VFA images using the Fabber process %s" %
            __version__)
        vbox.addWidget(title)

        cite = Citation(FAB_CITE_TITLE, FAB_CITE_AUTHOR, FAB_CITE_JOURNAL)
        vbox.addWidget(cite)

        grid = QtGui.QGridLayout()
        self.multivol_choice = ChoiceOption(
            "VFA data in",
            grid,
            ypos=0,
            choices=["Single data set", "Multiple data sets"])
        self.multivol_choice.combo.currentIndexChanged.connect(self.update_ui)

        self.multivol_label = QtGui.QLabel("VFA data set")
        grid.addWidget(self.multivol_label, 1, 0)
        self.multivol_combo = OverlayCombo(self.ivm)
        grid.addWidget(self.multivol_combo, 1, 1)
        self.multivol_fas_label = QtGui.QLabel("FAs (\N{DEGREE SIGN})")
        grid.addWidget(self.multivol_fas_label, 2, 0)
        self.multivol_fas = NumberList(initial=[
            1,
        ])
        grid.addWidget(self.multivol_fas, 2, 1, 1, 2)

        self.singlevol_label = QtGui.QLabel("VFA data sets")
        grid.addWidget(self.singlevol_label, 3, 0)
        grid.setAlignment(self.singlevol_label, QtCore.Qt.AlignTop)
        self.singlevol_table = QtGui.QTableWidget()
        self.singlevol_table.setColumnCount(2)
        self.singlevol_table.setHorizontalHeaderLabels(
            ["Data set", "Flip angle"])
        self.singlevol_table.setEditTriggers(
            QtGui.QAbstractItemView.NoEditTriggers)
        grid.addWidget(self.singlevol_table, 3, 1)

        hbox = QtGui.QHBoxLayout()
        self.singlevol_add = QtGui.QPushButton("Add")
        self.singlevol_add.clicked.connect(self.add_vol)
        hbox.addWidget(self.singlevol_add)
        self.singlevol_clear = QtGui.QPushButton("Clear")
        self.singlevol_clear.clicked.connect(self.clear_vols)
        hbox.addWidget(self.singlevol_clear)
        grid.addLayout(hbox, 4, 1)

        self.tr = NumericOption("TR (ms)",
                                grid,
                                ypos=5,
                                default=4.108,
                                minval=0,
                                step=0.1,
                                decimals=3)

        grid.setColumnStretch(3, 1)

        vbox.addLayout(grid)

        self.run = RunBox(self.get_process, self.get_rundata)
        vbox.addWidget(self.run)

        vbox.addStretch(1)
        self.update_ui()
def get_struc_models():
    ret = {}
    for cls in get_plugins("datasim-struc-models"):
        ret[cls.NAME] = cls
    return ret
示例#24
0
 def __init__(self, ivm, title):
     DataModel.__init__(self, ivm, title)
     from fabber import Fabber
     search_dirs = get_plugins(key="fabber-dirs")
     self._fab = Fabber(*search_dirs)