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)
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
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))
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)
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
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
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
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
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
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
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)
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
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), )
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
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)
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)
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
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)
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
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
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
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()
def _load(self, context: ILoadingContext) -> None: context.load(_ChildField(), _get_dummy_node())
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)
def _load(self, context: ILoadingContext) -> None: context.error(ErrorCode.VALUE_ERROR, "Test message")
def load(self, context: ILoadingContext, field: IBaseField) -> Node: return context.current_node()
def _load(self, context: ILoadingContext) -> None: assert context.current_location() == location