strictyaml icon indicating copy to clipboard operation
strictyaml copied to clipboard

The type order of optional arguments affects the results

Open fouzhe opened this issue 3 years ago • 2 comments

I used version: 1.6.1. The following program is correct:

s = "mode: default"

schema_map = {
    "mode": sy.Str(),
    sy.Optional("duration", default=None, drop_if_none=False): sy.EmptyNone()
    | sy.Float(),
}

config_yaml = sy.load(
    yaml_string=s,
    schema=sy.Map(schema_map),
)

But when I change the type order of optional duration like following:

s = "mode: default"

schema_map = {
    "mode": sy.Str(),
    sy.Optional("duration", default=None, drop_if_none=False): sy.Float()
    | sy.EmptyNone(),
}

config_yaml = sy.load(
    yaml_string=s,
    schema=sy.Map(schema_map),
)

then there would be an error, here is the error log:

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../vendor/lib/python3.10/site-packages/strictyaml/parser.py:323: in load
    return generic_load(yaml_string, schema=schema, label=label)
../vendor/lib/python3.10/site-packages/strictyaml/parser.py:301: in generic_load
    return schema(YAMLChunk(document, label=label))
../vendor/lib/python3.10/site-packages/strictyaml/validators.py:17: in __call__
    self.validate(chunk)
../vendor/lib/python3.10/site-packages/strictyaml/compound.py:180: in validate
    new_value = value_validator(
../vendor/lib/python3.10/site-packages/strictyaml/validators.py:107: in __call__
    result = self._validator_a(chunk)
../vendor/lib/python3.10/site-packages/strictyaml/scalar.py:27: in __call__
    return YAML(chunk, validator=self)
../vendor/lib/python3.10/site-packages/strictyaml/representation.py:63: in __init__
    self._value = validator.validate(value)
../vendor/lib/python3.10/site-packages/strictyaml/scalar.py:30: in validate
    return self.validate_scalar(chunk)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Float()
chunk = <strictyaml.yamllocation.YAMLChunk object at 0x7f64f2212aa0>

    def validate_scalar(self, chunk):
        val = chunk.contents
        if utils.is_infinity(val) or utils.is_not_a_number(val):
            val = val.replace(".", "")
        elif not utils.is_decimal(val):
            chunk.expecting_but_found("when expecting a float")
        # Only Python 3.6+ supports underscores in numeric literals
>       return float(val.replace("_", ""))
E       ValueError: could not convert string to float: ''

../vendor/lib/python3.10/site-packages/strictyaml/scalar.py:230: ValueError

But if changing sy.Float() to sy.Int(), this error would not arise.

fouzhe avatar Sep 19 '22 12:09 fouzhe

is_decimal is using regex pattern which matches empty string and therefore returns False Positive result.

Adding two lines to is_decimal before existing return ...:

if not value:
    return False

Would fix the issue.

I would do a PR, but it looks like they are not processed / handled for now.

wikiped avatar Jul 26 '23 16:07 wikiped

@wikiped Thanks!

fouzhe avatar Jul 30 '23 08:07 fouzhe