Ejemplo n.º 1
0
    def writeInitCodeJS(self, buff):
        inits = getInitVals(self.params)
        for param in inits:
            if inits[param].val in ['', None, 'None', 'none']:
                inits[param].val = 'undefined'

        # Check for unsupported units
        if inits['units'].val == 'from exp settings':
            inits['units'] = copy.copy(self.exp.settings.params['Units'])
        if inits['units'].val in ['cm', 'deg', 'degFlatPos', 'degFlat']:
            msg = ("'{units}' units for your '{name}' Slider are not currently supported for PsychoJS: "
                  "switching units to 'height'. Note, this will affect the size and positioning of '{name}'.")
            logging.warning(msg.format(units=inits['units'].val, name=inits['name'].val))
            inits['units'].val = "height"

        boolConverter = {False: 'false', True: 'true'}
        sliderStyles = {'slider': 'SLIDER',
                        'scrollbar': 'SLIDER',
                        '()': 'RATING',
                        'rating': 'RATING',
                        'radio': 'RADIO',
                        'labels45': 'LABELS_45',
                        'whiteOnBlack': 'WHITE_ON_BLACK',
                        'triangleMarker': 'TRIANGLE_MARKER'}

        # If no style given, set default 'rating' as list
        if len(inits['styles'].val) == 0:
            inits['styles'].val = 'rating'

        # reformat styles for JS
        # concatenate styles and tweaks
        tweaksList = utils.listFromString(self.params['styleTweaks'].val)
        if type(inits['styles'].val) == list:  # from an experiment <2021.1
            stylesList = inits['styles'].val + tweaksList
        else:
            stylesList = [inits['styles'].val] + tweaksList
        stylesListJS = [sliderStyles[this] for this in stylesList]
        # if not isinstance(inits['styleTweaks'].val, (tuple, list)):
        #     inits['styleTweaks'].val = [inits['styleTweaks'].val]
        # inits['styleTweaks'].val = ', '.join(["visual.Slider.StyleTweaks.{}".format(adj)
        #                                       for adj in inits['styleTweaks'].val])

        # convert that to string and JS-ify
        inits['styles'].val = py2js.expression2js(str(stylesListJS))
        inits['styles'].valType = 'code'

        inits['depth'] = -self.getPosInRoutine()

        # build up an initialization string for Slider():
        initStr = ("{name} = new visual.Slider({{\n"
                   "  win: psychoJS.window, name: '{name}',\n"
                   "  size: {size}, pos: {pos}, units: {units},\n"
                   "  labels: {labels}, ticks: {ticks},\n"
                   "  granularity: {granularity}, style: {styles},\n"
                   "  color: new util.Color({color}), \n"
                   "  fontFamily: {font}, bold: true, italic: false, depth: {depth}, \n"
                   ).format(**inits)
        initStr += ("  flip: {flip},\n"
                    "}});\n\n").format(flip=boolConverter[inits['flip'].val])
        buff.writeIndentedLines(initStr)
Ejemplo n.º 2
0
def test_listFromString():
    assert ['yes', 'no'] == utils.listFromString("yes, no")
    assert ['yes', 'no'] == utils.listFromString("[yes, no]")
    assert ['yes', 'no'] == utils.listFromString("(yes, no)")
    assert ['yes', 'no'] == utils.listFromString("'yes', 'no'")
    assert ['yes', 'no'] == utils.listFromString("['yes', 'no']")
    assert ['yes', 'no'] == utils.listFromString("('yes', 'no')")
    # this should be returned without ast.literal_eval being used
    assert ['yes', 'no'] == utils.listFromString(('yes', 'no'))
    # this would create a syntax error in ast.literal_eval
    assert ["Don't", "Do"] == utils.listFromString("Don't, Do")
Ejemplo n.º 3
0
    def importItems(self, items):
        """Import items from csv or excel sheet and convert to list of dicts.
        Will also accept a list of dicts.

        Note, for csv and excel files, 'options' must contain comma separated values,
        e.g., one, two, three. No parenthesis, or quotation marks required.

        Parameters
        ----------
        items :  Excel or CSV file, list of dicts
            Items used to populate the Form

        Returns
        -------
        List of dicts
            A list of dicts, where each list entry is a dict containing all fields for a single Form item
        """
        def _checkSynonyms(items, fieldNames):
            """Checks for updated names for fields (i.e. synonyms)"""

            replacedFields = set()
            for field in _synonyms:
                synonym = _synonyms[field]
                for item in items:
                    if synonym in item:
                        # convert to new name
                        item[field] = item[synonym]
                        del item[synonym]
                        replacedFields.add(field)
            for field in replacedFields:
                fieldNames.append(field)
                fieldNames.remove(_synonyms[field])
                logging.warning("Form {} included field no longer used {}. "
                                "Replacing with new name '{}'".format(
                                    self.name, _synonyms[field], field))

        def _checkRequiredFields(fieldNames):
            """Checks for required headings (do this after checking synonyms)"""
            for hdr in _knownFields:
                # is it required and/or present?
                if _knownFields[hdr] == _REQUIRED and hdr not in fieldNames:
                    raise ValueError("Missing header ({}) in Form ({}). "
                                     "Headers found were: {}".format(
                                         hdr, self.name, fieldNames))

        def _checkTypes(types, itemText):
            """A nested function for testing the number of options given

            Raises ValueError if n Options not > 1
            """
            itemDiff = set([types]) - set(_knownRespTypes)

            for incorrItemType in itemDiff:
                if incorrItemType == _REQUIRED:
                    if self._itemsFile:
                        itemsFileStr = ("in items file '{}'".format(
                            self._itemsFile))
                    else:
                        itemsFileStr = ""
                    msg = ("Item {}{} is missing a required "
                           "value for its response type. Permitted types are "
                           "{}.".format(itemText, itemsFileStr,
                                        _knownRespTypes))
                if self.autoLog:
                    logging.error(msg)
                raise ValueError(msg)

        def _addDefaultItems(items):
            """
            Adds default items when missing. Works in-place.

            Parameters
            ----------
            items : List of dicts
            headers : List of column headers for each item
            """
            def isPresent(d, field):
                # check if the field is there and not empty on this row
                return (field in d and d[field] not in [None, ''])

            missingHeaders = []
            defaultValues = _knownFields
            for index, item in enumerate(items):
                defaultValues['index'] = index
                for header in defaultValues:
                    # if header is missing of val is None or ''
                    if not isPresent(item, header):
                        oldHeader = header.replace('item', 'question')
                        if isPresent(item, oldHeader):
                            item[header] = item[oldHeader]
                            logging.warning(
                                "{} is a deprecated heading for Forms. "
                                "Use {} instead".format(oldHeader, header))
                            continue
                        # Default to colour scheme if specified
                        if defaultValues[header] in ['fg', 'bg', 'em']:
                            item[header] = self.colorScheme[
                                defaultValues[header]]
                        else:
                            item[header] = defaultValues[header]
                        missingHeaders.append(header)

            msg = "Using default values for the following headers: {}".format(
                missingHeaders)
            if self.autoLog:
                logging.info(msg)

        if self.autoLog:
            logging.info("Importing items...")

        if not isinstance(items, list):
            # items is a conditions file
            self._itemsFile = Path(items)
            items, fieldNames = importConditions(items, returnFieldNames=True)
        else:  # we already have a list so lets find the fieldnames
            fieldNames = set()
            for item in items:
                fieldNames = fieldNames.union(item)
            fieldNames = list(fieldNames)  # convert to list at the end
            self._itemsFile = None

        _checkSynonyms(items, fieldNames)
        _checkRequiredFields(fieldNames)
        # Add default values if entries missing
        _addDefaultItems(items)

        # Convert options to list of strings
        for idx, item in enumerate(items):
            if item['ticks']:
                item['ticks'] = listFromString(item['ticks'])
            if 'tickLabels' in item and item['tickLabels']:
                item['tickLabels'] = listFromString(item['tickLabels'])
            if 'options' in item and item['options']:
                item['options'] = listFromString(item['options'])

        # Check types
        [_checkTypes(item['type'], item['itemText']) for item in items]
        # Check N options > 1
        # Randomise items if requested
        if self.randomize:
            shuffle(items)
        return items