Getting UnboundLocalError
Hello,
I am getting a weird error when trying to run validate.
data = ["str"]
schema = {"minItems":1, "minLength": 1}
fastjsonschema.validate(schema, data)
gives
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../fastjsonschema/__init__.py", line 114, in validate
return compile(definition, handlers, formats, use_default)(data)
File "<string>", line 10, in validate
UnboundLocalError: local variable 'data_len' referenced before assignment
It seems like something goes wrong when using minItems/maxItems with minLength/maxLength?
@jinsoo960 Arrays can be validated with minItems/maxItems while Strings can be validated with minLength/maxLength as per the JSON Schema specification. There is an implicit type check (list/tuple for minItems/maxItems, str for minLength/maxLength) along with the length validation. Using minItems along with minLength is arguably an illegal operation since they validate different data types.
https://json-schema.org/draft/2020-12/json-schema-validation.html#name-minlength https://json-schema.org/draft/2020-12/json-schema-validation.html#name-maxlength https://json-schema.org/draft/2020-12/json-schema-validation.html#name-maxitems https://json-schema.org/draft/2020-12/json-schema-validation.html#name-minitems
Both minItems/maxItems and minLength/maxLength are using the same generator function create_variable_with_length, this generator function defines a variable {variable}_len to hold the length of the passed variable. This variable is defined in the generated code only if the object is of the appropriate type (str for minLength/maxLength, list/tuple for minItems/maxItems). However, the generator will always add it to its internal set of tracked variables (self._variables).
For instance, if the schema is:
{
"minItems": 1,
"minLength": 1
}
Since both minLength and minItems are defined, the generator will generate an if block with {variable}_len defined for validating minItems and add {variable_len} to its internal set of generated variables. When it generates the if block for validating minLength, it will not define {variable}_len since it has previously added it to its set of tracked variables.
The code block generated would be roughly of the form:
{variable}_is_list = isinstance({variable}, (list, tuple))
if {variable}_is_list:
{variable}_len = len({variable})
if {variable}_len < {minItems}:
raise JSONSchemaException(msg)
if isinstance({variable}, str):
if {variable}_len < {minLength}:
raise JSONSchemaException(msg)
Note that {variable}_len is not defined in the second if block.
If the passed object to validate is a string and not a list, {variable}_len would not be defined in the second if block as {variable}_is_list would be False and the contents of the first if block would not be evaluated.
My proposed fix is to add a separate generator function create_variable_with_items which creates a variable {variable}_items to hold the length of the variable and call this function from generate_min_items/generate_max_items instead thus resolving the variable name conflict described above. Now, minItems will effectively be ignored if the passed object is not a list or tuple while minLength will effectively be ignored if the passed object is not a str.
This is consistent with the behaviour of the online JSON Schema validator Hyperjump.
@horejsek - I have raised a PR for this.