Example #1
0
    def _load(self, context: ILoadingContext) -> Any:
        if not context.expect_scalar():
            return UNDEFINED

        current_node = context.current_node()
        string_value = current_node.value
        return self._convert(context, string_value)
Example #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
Example #3
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))
Example #4
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)
Example #5
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
Example #6
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
    def load(self, context: ILoadingContext, field: IBaseField) -> Any:
        if not context.expect_sequence():
            return UNDEFINED

        node = context.current_node()
        assert isinstance(node, SequenceNode)

        for child in node.value:
            result = context.load(field, child)
            if result is not UNDEFINED:
                return result

        return UNDEFINED
Example #8
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
Example #9
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
Example #10
0
    def _load(self, context: ILoadingContext) -> Any:
        if not context.expect_sequence():
            return UNDEFINED

        node = context.current_node()
        result = []
        for item_node in node.value:
            item = context.load(self._item_field, item_node)
            if item is UNDEFINED:
                continue

            result.append(item)

        return result
Example #11
0
    def _get_roots(self, context: ILoadingContext) -> Iterator[Path]:
        """Return the configured root directories."""
        if self._allow_relative:
            current_location = context.current_location()
            if current_location is not None:
                file_path = Path(current_location)
                parent = file_path.parent
                if parent.is_dir():
                    yield parent

        config = context.get_config(PathHandler.Config)
        if config is not None:
            for root in config.roots:
                yield root
Example #12
0
    def load(self, context: ILoadingContext, field: IBaseField) -> Any:
        if not context.expect_scalar(
            _("!env must be set on a string node containing the variable name.")
        ):
            return UNDEFINED

        node = context.current_node()
        var_name = node.value

        if var_name not in environ:
            return UNDEFINED

        fake_node = ScalarNode("", environ[var_name], node.start_mark, node.end_mark)

        return context.load(field, fake_node)
Example #13
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
Example #14
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),
        )
Example #15
0
    def _load(self, context: ILoadingContext) -> Any:
        node = context.current_node()
        if not context.expect_mapping():
            return UNDEFINED

        result = {}
        for key_node, value_node in node.value:
            assert isinstance(key_node, ScalarNode)
            key = key_node.value

            item = context.load(self._item_field, value_node)
            if item is UNDEFINED:
                continue

            result[key] = item

        return result
Example #16
0
    def load(self, context: ILoadingContext, field: IBaseField) -> Any:
        """See Resolver.resolve for usage."""
        if not context.expect_scalar(_("glob must be set on a scalar node")):
            return UNDEFINED

        node = context.current_node()
        glob = node.value
        result = []
        for root in self._get_roots(context):
            for path in root.glob(glob):
                if not path.is_file():
                    continue

                content = self._load_file(context, path)

                if content is not None:
                    result.append(content)

        fake_node = SequenceNode("", result, node.start_mark, node.end_mark)
        return context.load(field, fake_node)
Example #17
0
    def load(self, context: ILoadingContext, field: IBaseField) -> Any:
        node = context.current_node()
        tag = node.tag[1:]  # Remove trailing !
        match = self._compiled_pattern.match(tag)

        # The pattern should match already if we're here
        assert match is not None

        config = context.get_config(IfHandler.Config)
        flag = match.group("flag")

        if not config.is_defined(flag):
            return UNDEFINED

        # We need to return a copy of the node and erase the tag to avoid
        # the infinite recursion that would happen if we return a node with
        # an if tag still defined on it
        node_copy = copy(node)
        node_copy.tag = ""

        return context.load(field, node_copy)
Example #18
0
    def _get_file(self, context: ILoadingContext) -> Optional[Path]:
        node = context.current_node()
        file_path = Path(node.value)

        if file_path.is_absolute():
            return file_path

        for root in self._get_roots(context):
            path = root / file_path
            if path.is_file():
                return path

        return None
Example #19
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)
Example #20
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
Example #21
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
Example #22
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
Example #23
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()
Example #24
0
 def _load(self, context: ILoadingContext) -> None:
     context.load(_ChildField(), _get_dummy_node())
Example #25
0
 def validate(cls, context: ILoadingContext) -> None:
     """Validate that context as correct current_node_path."""
     nonlocal validate_called
     validate_called = True
     assert context.current_location() == str(file_path)
Example #26
0
 def _load(self, context: ILoadingContext) -> None:
     context.error(ErrorCode.VALUE_ERROR, "Test message")
Example #27
0
 def load(self, context: ILoadingContext, field: IBaseField) -> Node:
     return context.current_node()
Example #28
0
 def _load(self, context: ILoadingContext) -> None:
     assert context.current_location() == location