Ejemplo n.º 1
0
    def conduct(self):
        '''
        Run control & candidate functions and return the control's return value.
        ``control()`` must be called first.

        :raise LaboratoryException: when no control case has been set
        :return: Control function's return value
        '''
        if self._control is None:
            raise exceptions.LaboratoryException(
                'Your experiment must contain a control case'
            )


        # execute control and exit if experiment is not enabled
        if not self.enabled():
            control = self._run_tested_func(raise_on_exception=True, **self._control)
            return control.value

        # otherwise, let's wrap an executor around all of our functions and randomise the ordering

        def get_func_executor(obs_def, is_control):
            """A lightweight wrapper around a tested function in order to retrieve state"""
            return lambda *a, **kw: (self._run_tested_func(raise_on_exception=is_control, **obs_def), is_control)

        control = self._run_tested_func(raise_on_exception=True, **self._control)
        funcs = [get_func_executor(cand, is_control=False,) for cand in self._candidates]

        thr = threading.Thread(target=self.run_candidates, args=(control, funcs), kwargs={})
        thr.start()

        return control.value
Ejemplo n.º 2
0
    def control(self,
                control_func,
                args=None,
                kwargs=None,
                name='Control',
                context=None):
        '''
        Set the experiment's control function. Must be set before ``conduct()`` is called.

        :param callable control_func: your control function
        :param iterable args: positional arguments to pass to your function
        :param dict kwargs: keyword arguments to pass to your function
        :param string name: a name for your observation
        :param dict context: observation-specific context

        :raises LaboratoryException: If attempting to set a second control case
        '''
        if self._control is not None:
            raise exceptions.LaboratoryException(
                'You have already established a control case')

        self._control = {
            'func': control_func,
            'args': args or [],
            'kwargs': kwargs or {},
            'name': name,
            'context': context or {},
        }
Ejemplo n.º 3
0
    def conduct(self, randomize=True):
        '''
        Run control & candidate functions and return the control's return value.
        ``control()`` must be called first.

        :param bool randomize: controls whether we shuffle the order
            of execution between control and candidate
        :raise LaboratoryException: when no control case has been set
        :return: Control function's return value
        '''
        if self._control is None:
            raise exceptions.LaboratoryException(
                'Your experiment must contain a control case')

        # execute control and exit if experiment is not enabled
        if not self.enabled():
            control = self._run_tested_func(raise_on_exception=True,
                                            **self._control)
            return control.value

        # otherwise, let's wrap an executor around all of our functions and randomise the ordering

        def get_func_executor(obs_def, is_control):
            """A lightweight wrapper around a tested function in order to retrieve state"""
            return lambda *a, **kw: (self._run_tested_func(
                raise_on_exception=is_control, **obs_def), is_control)

        funcs = [
            get_func_executor(self._control, is_control=True),
        ] + [
            get_func_executor(
                cand,
                is_control=False,
            ) for cand in self._candidates
        ]

        if randomize:
            random.shuffle(funcs)

        control = None
        candidates = []

        # go through the randomised list and execute the functions
        for func in funcs:
            observation, is_control = func()
            if is_control:
                control = observation
            else:
                candidates.append(observation)

        result = Result(self, control, candidates)

        try:
            self.publish(result)
        except Exception:
            msg = 'Exception occured when publishing %s experiment data'
            logger.exception(msg % self.name)

        return control.value
Ejemplo n.º 4
0
    def run(self):
        if self._control is None:
            raise exceptions.LaboratoryException(
                'Your experiment must record a control case')

        result = Result(self, self._control, self._observations)

        try:
            self.publish(result)
        except Exception as e:
            msg = 'Exception occured when publishing %s experiment data'
            logger.exception(msg % self.name)

        return self._control.value