Ejemplo n.º 1
0
    def load(self, context: ILoadingContext, field: IBaseField) -> Any:
        """See Resolver.resolve for usage."""
        if not context.expect_scalar(
            _("import / try-import must be set on a scalar node")
        ):
            return UNDEFINED

        file_path = self._get_file(context)
        if file_path is None:
            node = context.current_node()
            if node.tag == "!import":
                context.error(
                    ErrorCode.IMPORT_NOT_FOUND,
                    _("Unable to find {} in any of the configured directories"),
                    node.value,
                )

            return UNDEFINED

        file_yaml_node = self._load_file(context, file_path)

        if file_yaml_node is None:
            return UNDEFINED

        return context.load(field, file_yaml_node, str(file_path))
Ejemplo n.º 2
0
def _load(obj: Any, context: ILoadingContext,
          config: ObjectField.Config) -> Any:
    fields = config.get_fields(obj)

    node = context.current_node()
    set_fields = set()

    for name_node, value_node in node.value:
        field_name = context.load(StringField(), name_node)
        if field_name is UNDEFINED:
            continue

        field_name = name_node.value
        set_fields.add(field_name)
        if field_name not in fields:
            context.error(ErrorCode.FIELD_NOT_DECLARED,
                          _("Field {} is not declared."), field_name)
            continue

        field = fields[field_name]
        field_value = context.load(field, value_node)
        if field_value is UNDEFINED:
            continue

        setattr(obj, field_name, field_value)

    if _validate(obj, fields, set_fields, context, config):
        post_load = config.get_hook(obj, "post_load")
        if post_load is not None:
            post_load()

        return obj

    return UNDEFINED
Ejemplo n.º 3
0
    def _convert(self, context: ILoadingContext, value: str) -> Any:
        try:
            result = float(value)
        except ValueError:
            context.error(ErrorCode.VALUE_ERROR,
                          _('Can\'t convert "{}" to a float'), value)
            return UNDEFINED

        return ScalarField._check_in_bounds(context, result, self._minimum,
                                            self._maximum)
Ejemplo n.º 4
0
    def _convert(self, context: ILoadingContext, value: str) -> Any:
        if self._pattern is not None and not self._pattern.match(value):
            context.error(
                ErrorCode.VALIDATION_ERROR,
                _("Value {} doesn't match required pattern {}"),
                value,
                self._pattern_str,
            )
            return UNDEFINED

        return value
Ejemplo n.º 5
0
    def _convert(self, context: ILoadingContext, value: str) -> Any:
        for member in self._enum_class:
            if member.name == value:
                return member

        context.error(
            ErrorCode.VALIDATION_ERROR,
            _("Unkown value {} for enum {}."),
            value,
            self._enum_class,
        )
        return UNDEFINED
Ejemplo n.º 6
0
 def _load_file(context: ILoadingContext, path: Path) -> Optional[Node]:
     """Load a YAML document, emit a MarshPyError on ParseError."""
     with open(path, "r", encoding="utf-8") as yaml_file:
         try:
             return cast(Node, compose(yaml_file))  # type: ignore
         except ParserError as error:
             context.error(
                 ErrorCode.VALUE_ERROR,
                 _("Parse error while loading {} : {}"),
                 path,
                 error,
             )
     return None
Ejemplo n.º 7
0
    def _convert(self, context: ILoadingContext, value: str) -> Any:
        if value in _TRUE_VALUES:
            return True

        if value in _FALSE_VALUES:
            return False

        context.error(
            ErrorCode.VALUE_ERROR,
            _("Boolean value should be one of {}"),
            ", ".join(_TRUE_VALUES + _FALSE_VALUES),
        )

        return UNDEFINED
Ejemplo n.º 8
0
    def _convert(self, context: ILoadingContext, value: str) -> Any:
        result: Optional[int] = None

        try:
            result = int(value, self._base)
        except ValueError:
            context.error(ErrorCode.VALUE_ERROR,
                          _('Can\'t convert "{}" to an integer'), value)
            return UNDEFINED

        return cast(
            Optional[int],
            ScalarField._check_in_bounds(context, result, self._minimum,
                                         self._maximum),
        )
Ejemplo n.º 9
0
    def _convert(self, context: ILoadingContext, value: str) -> Any:
        path = Path(value)

        if not path.is_absolute() and not path.exists():
            location_str = context.current_location()
            if location_str is not None:
                location = Path(location_str)
                parent = location.parent
                path = parent / path

        if self._must_exist and not path.exists():
            context.error(ErrorCode.VALIDATION_ERROR, _("Cannot find path {}."), path)
            return UNDEFINED

        return path
Ejemplo n.º 10
0
def _validate(
    obj: Any,
    fields: Dict[str, IBaseField],
    set_fields: Set[str],
    context: ILoadingContext,
    config: ObjectField.Config,
) -> bool:
    valid_object = True
    for name, field in fields.items():
        if field.required and name not in set_fields:
            valid_object = False
            context.error(ErrorCode.MISSING_REQUIRED_FIELD,
                          _("Missing required field {}"), name)

    hook = config.get_hook(obj, "validate")

    if hook is not None:
        validation_context = ValidationContext(context)
        hook(validation_context)
        valid_object = valid_object and not validation_context.has_error()

    return valid_object
Ejemplo n.º 11
0
    def _load(self, context: ILoadingContext) -> Any:
        if not context.expect_mapping():
            return UNDEFINED

        config = context.get_config(ObjectField.Config)
        node = context.current_node()
        tag = str(node.tag)
        if tag.startswith("!type"):
            splitted_tag = tag.split(":")
            if len(splitted_tag) != 2:
                context.error(ErrorCode.BAD_TYPE_TAG_FORMAT, _TYPE_FORMAT_MSG,
                              tag)
                return None
            type_name = splitted_tag[1]
            obj = config.create(type_name, context)
        else:
            obj = self._object_class()

        if obj is None:
            return UNDEFINED

        return _load(obj, context, config)
Ejemplo n.º 12
0
    def _check_in_bounds(
        context: ILoadingContext,
        value: Union[int, float],
        minimum: Optional[Union[int, float]],
        maximum: Optional[Union[int, float]],
    ) -> Any:
        if minimum is not None and value < minimum:
            context.error(
                ErrorCode.VALIDATION_ERROR,
                _("Value is too small (minimum : {})"),
                minimum,
            )
            return UNDEFINED

        if maximum is not None and value > maximum:
            context.error(
                ErrorCode.VALIDATION_ERROR,
                _("Value is too big (maximum : {})"),
                maximum,
            )
            return UNDEFINED

        return value
Ejemplo n.º 13
0
    def load(self, context: ILoadingContext, field: IBaseField) -> Any:
        if not context.expect_sequence():
            return UNDEFINED

        node = context.current_node()

        result: Optional[Union[Dict[str, Any], List[Any]]] = None
        for child in node.value:
            child_result = context.load(field, child)
            if child_result is UNDEFINED:
                continue

            if isinstance(child_result, dict):
                if result is None:
                    result = {}

                assert isinstance(result, dict)
                result.update(child_result)

            elif isinstance(child_result, list):
                if result is None:
                    result = []

                assert isinstance(result, list)
                result += child_result

            else:
                msg = _("Trying to merge invalid object {}, expected dict or "
                        "list")
                context.error(ErrorCode.VALUE_ERROR, msg, result)

        # If nothing it's to merge, return UNDEFINED
        if result is None:
            return UNDEFINED

        return result
Ejemplo n.º 14
0
        def _default_object_factory(
                type_name: str,
                context: ILoadingContext) -> Optional[Type[Any]]:
            splitted_name = type_name.split(".")

            if len(splitted_name) < 2:
                context.error(ErrorCode.BAD_TYPE_TAG_FORMAT, _TYPE_FORMAT_MSG,
                              type_name)
                return None

            module_name = ".".join(splitted_name[:-1])
            class_name = splitted_name[-1]

            try:
                module = __import__(module_name, fromlist=class_name)
            except ModuleNotFoundError:
                context.error(
                    ErrorCode.TYPE_RESOLVE_ERROR,
                    _("Can't find python module for type {}"),
                    type_name,
                )
                return None

            if not hasattr(module, class_name):
                context.error(
                    ErrorCode.TYPE_RESOLVE_ERROR,
                    _("Can't find python type {}"),
                    type_name,
                )
                return None

            resolved_type = getattr(module, class_name)

            if not isclass(resolved_type):
                context.error(
                    ErrorCode.TYPE_RESOLVE_ERROR,
                    _("Python type {} is not a class"),
                    type_name,
                )
                return None

            return resolved_type()
Ejemplo n.º 15
0
 def _load(self, context: ILoadingContext) -> None:
     context.error(ErrorCode.VALUE_ERROR, "Test message")