예제 #1
0
def _validate_variable_data(question_name, var_name, var_data):
    # type: (str, str, Dict[str, Any]) -> bool
    """Perform validation on variable metadata and fix style if necessary.

    :raises QuestionValidationException if metadata is invalid.
    """
    var_type = var_data.get('type', '').strip()
    if not var_type:
        raise QuestionValidationException(
            "Question {} is missing type for variable {}".format(
                question_name,
                var_name))
    var_data['type'] = var_type

    var_desc = var_data.get('description', '').strip()
    if not var_desc:
        raise QuestionValidationException(
            "Question {} is missing description for variable {}".format(
                question_name,
                var_name))
    if not var_desc.endswith('.'):
        var_desc += '.'
    var_data['description'] = var_desc

    return True
예제 #2
0
파일: util.py 프로젝트: yrll/pybatfish
def validate_question_name(name):
    # type: (str) -> bool
    """Check if a question name is valid.

    :param name: question name
    :type name: str
    :returns True if the question name is valid
    :raises QuestionValidationException if the name is not valid
    """
    try:
        if "/" in name:
            raise QuestionValidationException(
                "Question name cannot contain slashes ('/')"
            )
        if len(name) > _MAX_FILENAME_LEN:
            raise QuestionValidationException(
                "Question name cannot be longer than {} characters".format(
                    _MAX_FILENAME_LEN
                )
            )
    except (TypeError, AttributeError):
        raise QuestionValidationException(
            "Question name has the wrong type ({}), a string is expected".format(
                type(name)
            )
        )
    return True
예제 #3
0
def _load_question_dict(question):
    # type: (Dict[str, Any]) -> Tuple[str, QuestionMeta]
    """Create a question from a dictionary which contains a template.

    :return the name of the question
    """
    # Perform series of validations on the question.
    # Try to have meaningful error messages.

    # Check has instance data
    instance_data = question.get('instance')
    if not instance_data:
        raise QuestionValidationException("Missing instance data")

    # name validation
    given_question_name = instance_data.get('instanceName')
    if not given_question_name or not validate_question_name(
            given_question_name):
        raise QuestionValidationException(
            "Invalid question name: {}".format(given_question_name))
    question_name = str(given_question_name)  # type: str

    # description validation
    question_description = instance_data.get(
        'description', '').strip()  # type: str
    if not question_description:
        raise QuestionValidationException(
            "Missing description for question '{}'".format(question_name))
    if not question_description.endswith('.'):
        question_description += '.'

    # Extend description if we can
    long_description = instance_data.get(
        'longDescription', '').strip()  # type: str
    if long_description:
        if not long_description.endswith('.'):
            long_description += '.'
        question_description = "\n\n".join(
            [question_description, long_description])

    # Extract question tags
    tags = sorted(map(str, instance_data.get('tags', [])))
    _tags.update(tags)

    # Validate question variables
    ivars = instance_data.get('variables')
    variables = _process_variables(question_name, ivars)

    # Compute docstring
    docstring = _compute_docstring(question_description, variables, ivars)

    # Make new Question class
    question_class = QuestionMeta(question_name, (QuestionBase,), {
        'docstring': docstring,
        'description': question_description,
        'tags': tags,
        'template': deepcopy(question),
        'variables': variables,
    })
    return question_name, question_class
예제 #4
0
        def constructor(self, *args, **kwargs):
            """Create a new question."""
            # Reject positional args; this way is PY2-compliant
            if args:
                raise TypeError("Please use keyword arguments")

            # Call super (i.e., QuestionBase)
            super(new_cls, self).__init__(new_cls.template, new_cls.session)

            # Update well-known params, if passed in
            if "exclusions" in kwargs:
                self._dict['exclusions'] = kwargs.get("exclusions")
            if "question_name" in kwargs:
                self._dict['instance']['instanceName'] = kwargs.get(
                    "question_name")
            else:
                self._dict['instance']['instanceName'] = ("__{}_{}".format(
                    self._dict['instance']['instanceName'], get_uuid()))

            # Validate that we are not accepting invalid kwargs/variables
            instance_vars = self._dict['instance'].get('variables', {})
            allowed_kwargs = set(instance_vars)
            allowed_kwargs.update(additional_kwargs)
            var_difference = set(kwargs.keys()).difference(allowed_kwargs)
            if var_difference:
                raise QuestionValidationException(
                    "Received unsupported parameters/variables: {}".format(
                        var_difference))
            # Set question-specific parameters
            for var_name, var_value in kwargs.items():
                if var_name not in additional_kwargs:
                    instance_vars[var_name]['value'] = var_value
예제 #5
0
        def constructor(self, question_name=None,
                        exclusions=None, **kwargs):
            """Create a new question."""
            # Call super (i.e., QuestionBase)
            super(new_cls, self).__init__(new_cls.template)

            # Update well-known params, if passed in
            if exclusions is not None:
                self._dict['exclusions'] = exclusions
            if question_name:
                self._dict['instance']['instanceName'] = question_name
            else:
                self._dict['instance']['instanceName'] = (
                    "__{}_{}".format(
                        self._dict['instance']['instanceName'], get_uuid()))

            # Validate that we are not accepting invalid kwargs/variables
            instance_vars = self._dict['instance'].get('variables', {})
            var_difference = set(kwargs.keys()).difference(instance_vars)
            if var_difference:
                raise QuestionValidationException(
                    "Received unsupported parameters/variables: {}".format(
                        var_difference))
            # Set question-specific parameters
            for var_name, var_value in kwargs.items():
                instance_vars[var_name]['value'] = var_value
예제 #6
0
def _validate_variable_data(question_name, var_name, var_data):
    # type: (str, str, Dict[str, Any]) -> bool
    """Perform validation on variable metadata.

    :raises QuestionValidationException if metadata is invalid.
    """
    if var_data.get('type') is None:
        raise QuestionValidationException(
            "Question {} is missing type for variable {}".format(
                question_name, var_name))

    if var_data.get('description') is None:
        raise QuestionValidationException(
            "Question {} is missing description for variable {}".format(
                question_name, var_name))
    return True
예제 #7
0
def _validate_variable_name(question_name, var_name):
    # type: (str, str) -> bool
    """Check if the variable name is valid."""
    if not re.match(_VALID_VARIABLE_NAME_REGEX, var_name):
        raise QuestionValidationException(
            "Question {} has invalid variable name: {}. Only alphanumeric characters are allowed"
            .format(question_name, var_name))
    return True
예제 #8
0
파일: util.py 프로젝트: cgmcintyr/pybatfish
def validate_json_path_regex(s):
    # type: (str) -> bool
    """Check if the given string is a valid JsonPath regex.

    :param s: string to check
    :type s: str
    :return True if `s` is valid
    :raises QuestionValidationException if `s` is not valid
    """
    if not s.startswith('/'):
        raise QuestionValidationException(
            "Expected '/' at the start of JsonPath regex")

    if not (s.endswith('/i') or s.endswith('/')):
        raise QuestionValidationException(
            "JsonPath regex must end with either '/' or '/i'")

    return True
예제 #9
0
def _load_question_disk(question_path, session):
    # type: (str, Session) -> Tuple[str, QuestionMeta]
    """Load a question template from disk and instantiate a new `:py:class:Question`."""
    with open(question_path, 'r') as question_file:
        question_dict = json.load(question_file)
    try:
        return _load_question_dict(question_dict, session)
    except QuestionValidationException as e:
        raise QuestionValidationException(
            "Error loading question from {}".format(question_path), e)
예제 #10
0
def _validate(questionJson):
    valid = True
    errorMessage = '\n'
    instanceData = questionJson['instance']
    if 'variables' in instanceData:
        variables = instanceData['variables']
        for variableName, variable in variables.items():
            # First check for missing mandatory parameters
            optional = False
            if 'optional' in variable:
                optional = variable['optional']
            if not optional:
                if 'value' not in variable:
                    valid = False
                    errorMessage += "   Missing value for mandatory parameter: '" + variableName + "'\n"

            # Now do some dynamic type-checking
            allowed_values = _build_allowed_values(variable)
            if 'value' in variable:
                value = variable['value']
                variableType = variable['type']
                minLength = None
                if 'minLength' in variable:
                    minLength = variable['minLength']
                isArray = 'minElements' in variable
                if isArray:
                    if not isinstance(value, list):
                        valid = False
                        errorMessage += "   Expected a list for parameter: '" + variableName + "'\n"
                    else:
                        minElements = variable['minElements']
                        if len(value) < minElements:
                            valid = False
                            errorMessage += "   Number of elements provided for parameter: '" + variableName + "' less than the minimum: " + str(
                                minElements) + "\n"
                        else:
                            for i in range(0, len(value)):
                                valueElement = value[i]
                                typeValid = _validateType(
                                    valueElement, variableType)
                                if not typeValid:
                                    valid = False
                                    errorMessage += "   Expected type: '" + variableType + "' for element: " + str(
                                        i
                                    ) + " of parameter: " ' + variableName + ' "\n"
                                elif minLength and len(
                                        valueElement) < minLength:
                                    valid = False
                                    errorMessage += "   Length of value: '" + valueElement + "' for element : " + str(
                                        i
                                    ) + " of parameter: '" + variableName + "' below minimum length: " + str(
                                        minLength) + "\n"
                                elif allowed_values is not None and valueElement not in \
                                        [v.name for v in allowed_values]:
                                    valid = False
                                    errorMessage += "   Value: '{}' is not among allowed values {} of parameter: '{}'\n".format(
                                        valueElement,
                                        [v.name for v in allowed_values],
                                        variableName)

                else:
                    typeValid, typeValidErrorMessage = _validateType(
                        value, variableType)
                    if not typeValid:
                        valid = False
                        if typeValidErrorMessage:
                            errorMessage += "   Expected type: '" + variableType + "' for parameter: '" + variableName + "'. Got error: '" + typeValidErrorMessage + "'\n"
                        else:
                            errorMessage += "   Expected type: '" + variableType + "' for parameter: '" + variableName + "'\n"
                    elif minLength and len(value) < minLength:
                        valid = False
                        errorMessage += "   Length of value: '" + value + "' for parameter: '" + variableName + "' below minimum length: " + str(
                            minLength) + "\n"
                    elif allowed_values is not None and value not in \
                            [v.name for v in allowed_values]:
                        valid = False
                        errorMessage += "   Value: '{}' is not among allowed values {} of parameter: '{}'\n".format(
                            value, [v.name for v in allowed_values],
                            variableName)
    if not valid:
        raise QuestionValidationException(errorMessage)
    return True
예제 #11
0
def _load_question_dict(question, session):
    # type: (Dict[str, Any], Session) -> Tuple[str, QuestionMeta]
    """Create a question from a dictionary which contains a template.

    :return the name of the question
    """
    # Perform series of validations on the question.
    # Try to have meaningful error messages.

    # Check has instance data
    instance_data = question.get("instance")
    if not instance_data:
        raise QuestionValidationException("Missing instance data")

    # name validation
    given_question_name = instance_data.get("instanceName")
    if not given_question_name or not validate_question_name(
            given_question_name):
        raise QuestionValidationException(
            "Invalid question name: {}".format(given_question_name))
    question_name = str(given_question_name)  # type: str

    # description validation
    question_description = instance_data.get("description",
                                             "").strip()  # type: str
    if not question_description:
        raise QuestionValidationException(
            "Missing description for question '{}'".format(question_name))
    if not question_description.endswith("."):
        question_description += "."

    # Extend description if we can
    long_description = instance_data.get("longDescription",
                                         "").strip()  # type: str
    if long_description:
        if not long_description.endswith("."):
            long_description += "."
        question_description = "\n\n".join(
            [question_description, long_description])

    # Extract question tags
    tags = sorted(map(str, instance_data.get("tags", [])))
    _tags.update(tags)

    # Validate question variables
    ivars = instance_data.get("variables", {})
    ordered_variable_names = instance_data.get("orderedVariableNames", [])
    variables = _process_variables(question_name, ivars,
                                   ordered_variable_names)

    # Compute docstring
    docstring = _compute_docstring(question_description, variables, ivars)

    # Make new Question class
    question_class = QuestionMeta(
        question_name,
        (QuestionBase, ),
        {
            "docstring": docstring,
            "description": question_description,
            "session": session,
            "tags": tags,
            "template": deepcopy(question),
            "variables": variables,
        },
    )
    return question_name, question_class
예제 #12
0
def _load_question_dict(question,
                        question_path=None,
                        module_name=bfq.__name__):
    # type: (Dict, Optional[str], str) -> str
    """Create a question from a dictionary which contains a template.

    :return the name of the question
    """
    # Perform series of validations on the question.
    # Try to have meaningful error messages.

    # Check has instance data
    instance_data = question.get('instance')
    if not instance_data:
        raise QuestionValidationException(
            "Missing instance data in question (file: {})".format(
                question_path))

    # name validation
    given_question_name = instance_data.get('instanceName')
    if not given_question_name or not validate_question_name(
            given_question_name):
        raise QuestionValidationException(
            "Invalid question name: {}".format(given_question_name))
    question_name = str(given_question_name)  # type: str

    # description validation
    question_description = instance_data.get('description')
    if not question_description:
        raise QuestionValidationException(
            "Missing description for question '{}'".format(question_name))

    # Extend description if we can
    long_description = instance_data.get('longDescription')
    if long_description:
        question_description = "\n".join(
            [question_description, long_description])

    # Extract question tags
    tags = sorted(map(str, instance_data.get('tags', [])))
    _tags.update(tags)

    # Validate question variables
    ivars = instance_data.get('variables')
    variables = _process_variables(question_name, ivars)

    # Compute docstring
    docstring = _compute_docstring(question_description, ivars)

    # Make new Question class and set it in the specified module
    module = sys.modules[module_name]
    setattr(
        module, question_name,
        QuestionMeta(
            question_name, (QuestionBase, ), {
                'docstring': docstring,
                'description': question_description,
                'module': module_name,
                'tags': tags,
                'template': deepcopy(question),
                'variables': variables,
            }))

    return question_name