python-openapi/openapi-core

[Bug]: UnboundLocalError: local variable 'value' referenced before assignment

andersk opened this issue · 4 comments

Actual Behavior

Traceback (most recent call last):
  File "/home/anders/python/openapi-core/test.py", line 38, in <module>
    validate_request(request, spec=spec)
  File "/home/anders/python/openapi-core/openapi_core/shortcuts.py", line 321, in validate_request
    validate_apicall_request(
  File "/home/anders/python/openapi-core/openapi_core/shortcuts.py", line 396, in validate_apicall_request
    return v.validate(request)
  File "/home/anders/python/openapi-core/openapi_core/validation/request/validators.py", line 278, in validate
    for err in self.iter_errors(request):
  File "/home/anders/python/openapi-core/openapi_core/validation/request/validators.py", line 341, in iter_errors
    yield from self._iter_errors(request, operation, path)
  File "/home/anders/python/openapi-core/openapi_core/validation/request/validators.py", line 114, in _iter_errors
    self._get_body(request.body, request.mimetype, operation)
  File "/home/anders/python/openapi-core/openapi_core/validation/decorators.py", line 31, in wrapper
    return f(*args, **kwds)
  File "/home/anders/python/openapi-core/openapi_core/validation/request/validators.py", line 260, in _get_body
    value, _ = self._get_content_and_schema(raw_body, content, mimetype)
  File "/home/anders/python/openapi-core/openapi_core/validation/validators.py", line 244, in _get_content_and_schema
    casted, schema = self._get_content_schema_value_and_schema(
  File "/home/anders/python/openapi-core/openapi_core/validation/validators.py", line 230, in _get_content_schema_value_and_schema
    deserialised = self._deserialise_media_type(
  File "/home/anders/python/openapi-core/openapi_core/validation/validators.py", line 118, in _deserialise_media_type
    return deserializer.deserialize(value)
  File "/home/anders/python/openapi-core/openapi_core/deserializing/media_types/deserializers.py", line 90, in deserialize
    return self.decode(deserialized)
  File "/home/anders/python/openapi-core/openapi_core/deserializing/media_types/deserializers.py", line 111, in decode
    properties[prop_name] = self.decode_property(
  File "/home/anders/python/openapi-core/openapi_core/deserializing/media_types/deserializers.py", line 138, in decode_property
    return self.decode_property_content_type(
  File "/home/anders/python/openapi-core/openapi_core/deserializing/media_types/deserializers.py", line 179, in decode_property_content_type
    return list(map(prop_deserializer.deserialize, value))
UnboundLocalError: local variable 'value' referenced before assignment

Expected Behavior

No error.

Steps to Reproduce

from openapi_core import Spec, validate_request
from openapi_core.testing import MockRequest

spec = Spec.from_dict(
    {
        "openapi": "3.1.0",
        "info": {"version": "0", "title": "test"},
        "paths": {
            "/test": {
                "post": {
                    "requestBody": {
                        "content": {
                            "application/x-www-form-urlencoded": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "foo": {"type": "array", "items": {"type": "string"}}
                                    },
                                },
                                "encoding": {"foo": {"contentType": "application/json"}},
                            }
                        }
                    },
                    "responses": {"200": {"description": "OK"}},
                }
            }
        },
    }
)

request = MockRequest(
    "http://localhost",
    "post",
    "/test",
    data='foo=["a","b","c"]',
    mimetype="application/x-www-form-urlencoded",
)
validate_request(request, spec=spec)

OpenAPI Core Version

current Git (0838a84)

OpenAPI Core Integration

none

Affected Area(s)

No response

References

No response

Anything else we need to know?

No response

Would you like to implement a fix?

None

Oh hmm, this might be user error? The request validates if I set "explode": False in the encoding object.

-                                "encoding": {"foo": {"contentType": "application/json"}},
+                                "encoding": {
+                                    "foo": {
+                                        "contentType": "application/json",
+                                        "explode": False,
+                                    }
+                                },

Still, UnboundLocalError is the wrong failure mode.

p1c2u commented

Hi @andersk

you use invalid data serialization strategy ?

["a","b","c"]

this doesn't seem to correct json

If you want to use style serialization then you don't need "contentype" just style/explode.

You don't even need encoding object because it default serialization strategy is style form (which I forgot to implement)

When passing complex objects in the application/x-www-form-urlencoded content type, the default serialization strategy of such properties is described in the Encoding Object's style property as form.

The UnboundLocalError is related to content type serialization, I will fix that also.

Thanks for your feedback.

Huh? It is correct JSON.

Python 3.10.12 (main, Jun  6 2023, 22:43:10) [GCC 12.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> json.loads('["a","b","c"]')
['a', 'b', 'c']

Without contentType: application/json, and with the default explode: true, style: form, the parameter would be serialized as foo=a&foo=b&foo=c; with explode: false, style: form, it would be serialized as foo=a,b,c. Neither serialization is compatible with the endpoint API I need to specify (and I can’t change the API, for backwards compatibility).

p1c2u commented

I get some confusion in drrialization process between those two similar examples:

application/x-www-form-urlencoded:
  schema:
    type: object
    properties:
      prop:
        type: array
        items:
          type: integer

and

multipart/form-data:
  schema:
    type: object
    properties:
      file:
        type: array
        items:
          type: string
          format: binary

I will make change . hope it will work