def test_if_tag_handler() -> None: """If tag should load value only if tag is defined.""" result = check_load( "!if(FLAG) test_value", field=StringField(), tag_handlers=[IfHandler()], config=[IfHandler.Config({"FLAG"})], ) assert result == "test_value" result = check_load( "!if(UNDEFINED) test_value", field=StringField(), tag_handlers=[IfHandler()], config=[IfHandler.Config({"FLAG"})], ) assert result == UNDEFINED result = check_load( "!if(FLAG) {key: value}", field=DictField(StringField()), tag_handlers=[IfHandler()], config=[IfHandler.Config({"FLAG"})], ) assert result == {"key": "value"} result = check_load( "!if(FLAG) [item]", field=ListField(StringField()), tag_handlers=[IfHandler()], config=[IfHandler.Config({"FLAG"})], ) assert result == ["item"]
def test_merge_tag_handler() -> None: """Merge tag handler should correctly merge dictionnaries & lists.""" # Merging list should work _check_merge_tag( ListField(StringField()), "!merge [[value_1, value_2], [value_3]]", ["value_1", "value_2", "value_3"], ) # Merging dicts should work _check_merge_tag( DictField(StringField()), "!merge [{a: a_value, b: b_value}, {b: overwrite_b}]", { "a": "a_value", "b": "overwrite_b" }, ) # An undefined value in the sequence should be ignored _check_merge_tag( ListField(StringField()), "!merge [[value_1, value_2], !fail [value_3]]", ["value_1", "value_2"], ) # An empty sequence should return UNDEFINED _check_merge_tag(ListField(StringField()), "!merge []", UNDEFINED)
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
class _Test: fields = {"list": ListField(StringField())} def __init__(self) -> None: """Initialize _Test.""" self.field: Optional[List[str]] = None
def test_merge_tag_handler_error_handling() -> None: """Merge tag should correctly handle errors.""" _check_merge_tag( ListField(StringField()), "!merge scalar_value", expected_error=ErrorCode.UNEXPECTED_NODE_TYPE, ) _check_merge_tag( ListField(StringField()), "!merge {}", expected_error=ErrorCode.UNEXPECTED_NODE_TYPE, ) _check_merge_tag(StringField(), "!merge [scalar_value]", expected_error=ErrorCode.VALUE_ERROR)
def _check_tag_error(yaml: str, expected_error: Optional[ErrorCode] = None) -> None: result = check_load( yaml, field=StringField(), expected_error=expected_error, tag_handlers=[EnvHandler()], ) assert result == UNDEFINED
class _TestObject: fields = {"test_field": StringField()} @classmethod 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 _check_first_of_tag(yaml: str, expected_value: Any = None, expected_error: Optional[ErrorCode] = None) -> None: if expected_error is not None: expected_value = UNDEFINED result = check_load( yaml, field=StringField(), tag_handlers=[FirstOfHandler()], expected_error=expected_error, ) assert result == expected_value
def check_path_tag_error( handler_type: Type[PathHandler], yaml: str, expected_error: ErrorCode, location: Optional[str] = None, allow_relative: bool = True, roots: Optional[List[Path]] = None, expected_value: Any = UNDEFINED, ) -> None: """Path tag hanhler inherited tags error test helper.""" result = check_load( yaml, field=ListField(StringField()), expected_error=expected_error, location=location, tag_handlers=[handler_type(allow_relative=allow_relative)], config=[PathHandler.Config(roots)], ) assert result == expected_value
class _OwnedChild(_Owned): fields = {"child_field": StringField()} def __init__(self) -> None: """Initialize object.""" super().__init__() self.child_field: Optional[str] = None self.child_validate_called = False self.child_post_load_called = False def validate(self, context: ValidationContext) -> None: """Validate.""" super().validate(context) self.child_validate_called = True def post_load(self) -> None: """Postload.""" super().post_load() self.child_post_load_called = True
def check_path_tag( handler_type: Type[PathHandler], yaml: str, expected_value: Any, allow_relative: bool = True, location: Optional[Path] = None, roots: Optional[List[Path]] = None, ) -> None: """Path tag hanhler inherited tags test helper.""" result = check_load( yaml, field=ListField(StringField()), tag_handlers=[handler_type(allow_relative=allow_relative)], config=[PathHandler.Config(roots=[] if roots is None else roots, )], location=str(location), ) # for glob tag handler. if isinstance(expected_value, list): assert sorted(result) == sorted(expected_value) else: assert result == expected_value
class _Owned: fields = { "required_field": StringField(required=True), "error": BoolField() } def __init__(self) -> None: """Initialize object.""" self.required_field: Optional[str] = None self.parent_validate_called = False self.parent_post_load_called = False def validate(self, context: ValidationContext) -> None: """Validate.""" if getattr(self, "error", False): context.error("Error") return self.parent_validate_called = True def post_load(self) -> None: """Postload.""" self.parent_post_load_called = True
class _Test: fields = {"field": StringField(validate=_validate)}
class _Owned: fields = {"test_field": StringField()} test_field: Optional[str] = None
def _field_resolver(obj: Any) -> Dict[str, IBaseField]: nonlocal resolver_called if obj.__class__ == _Object: resolver_called = True return dict(string_field=StringField()) return {}
from marshpy.fields.bool_field import BoolField from marshpy.fields.dict_field import DictField from marshpy.fields.float_field import FloatField from marshpy.fields.int_field import IntField from marshpy.fields.list_field import ListField from marshpy.fields.object_field import ObjectField from marshpy.fields.string_field import StringField from marshpy.tag_handlers.env_handler import EnvHandler from marshpy.tag_handlers.glob_handler import GlobHandler from marshpy.tag_handlers.if_handler import IfHandler from marshpy.tag_handlers.import_handler import ImportHandler from marshpy.tag_handlers.tag_handler import TagHandler _ROOT_FIELDS_MAPPING = { bool: BoolField(), dict: DictField(StringField()), float: FloatField(), int: IntField(), list: ListField(StringField()), str: StringField(), } ObjectType = TypeVar("ObjectType") def load( # pylint: disable=too-many-locals source: Union[str, IO[str]], object_class: Optional[Type[ObjectType]] = None, tag_handlers: Optional[Iterable[TagHandler]] = None, error_handler: Optional[ErrorHandler] = None, root_field: Optional[BaseField] = None,
class _Test: fields = {"string": StringField(pattern="^matching$")}
class _Test: fields = {"dict": DictField(StringField())} def __init__(self) -> None: """Initialize _Test.""" self.dict: Optional[Dict[str, str]] = None
class _Simple: fields = {"field": StringField()}
def _check_tag(yaml: str, expected: Any) -> None: result = check_load(yaml, field=StringField(), tag_handlers=[EnvHandler()]) assert result == expected