-
-
Notifications
You must be signed in to change notification settings - Fork 780
Description
Description
When using schema: type: number for a path parameter, it gives an error, ValueError: invalid literal for int() with base 10: '-21.5454'
Isn't it supposed to be possible to use number as a path parameter? If I use string or integer it works fine.
I'm really stumped here as to what's going on.
Expected behaviour
I expect the path parameters to be printed out in the console where I started my server when using the swagger ui to execute, as per my test controller function below (see Steps to reproduce)
Actual behaviour
When using latitude=64.5151
longitude=-21.5454
srid=4326
I get the error in description.
127.0.0.1 - - [14/Feb/2023 16:52:12] "GET /v1/lat/64.5151/long/-21.5454/srid/4326 HTTP/1.1" 500 -
Traceback (most recent call last):
File "/home/matthias/.local/share/virtualenvs/test-api-Hl7MEg6r/lib/python3.9/site-packages/flask/app.py", line 2548, in __call__
return self.wsgi_app(environ, start_response)
File "/home/matthias/.local/share/virtualenvs/test-api-Hl7MEg6r/lib/python3.9/site-packages/flask/app.py", line 2528, in wsgi_app
response = self.handle_exception(e)
File "/home/matthias/.local/share/virtualenvs/test-api-Hl7MEg6r/lib/python3.9/site-packages/flask_cors/extension.py", line 165, in wrapped_function
return cors_after_request(app.make_response(f(*args, **kwargs)))
File "/home/matthias/.local/share/virtualenvs/test-api-Hl7MEg6r/lib/python3.9/site-packages/flask/app.py", line 2524, in wsgi_app
ctx.push()
File "/home/matthias/.local/share/virtualenvs/test-api-Hl7MEg6r/lib/python3.9/site-packages/flask/ctx.py", line 383, in push
self.match_request()
File "/home/matthias/.local/share/virtualenvs/test-api-Hl7MEg6r/lib/python3.9/site-packages/flask/ctx.py", line 351, in match_request
result = self.url_adapter.match(return_rule=True) # type: ignore
File "/home/matthias/.local/share/virtualenvs/test-api-Hl7MEg6r/lib/python3.9/site-packages/werkzeug/routing/map.py", line 599, in match
result = self.map._matcher.match(domain_part, path_part, method, websocket)
File "/home/matthias/.local/share/virtualenvs/test-api-Hl7MEg6r/lib/python3.9/site-packages/werkzeug/routing/matcher.py", line 173, in match
value = rule._converters[name].to_python(value)
File "/home/matthias/.local/share/virtualenvs/test-api-Hl7MEg6r/lib/python3.9/site-packages/connexion/apps/flask_app.py", line 184, in to_python
return int(value)
ValueError: invalid literal for int() with base 10: '-21.5454'
Steps to reproduce
I've made a minimal yaml file which reproduces the issue:
openapi: 3.0.0
info:
title: Path param bug
version: 1.0.1
paths:
/lat/{latitude}/long/{longitude}/srid/{srid}:
get:
operationId: test_controller.test_coords
parameters:
- in: path
name: latitude
required: true
schema:
type: number
- in: path
name: longitude
required: true
schema:
type: number
- in: path
name: srid
required: true
schema:
type: integer
responses:
"200":
content: {}
description: OK
And with controller code:
def test_coords(*args, body={}, **kwargs):
print("lat:", kwargs["latitude"])
print("lon:", kwargs["longitude"])
print("srid:", kwargs["srid"])
Additional info:
This error happens before the controller code is run, and I managed to pinpoint part of the issue by setting breakpoints in my local lib files mentioned in the stack trace. I found out, that somehow, somewhere, connexion or flask or werkzeug changes the float path parameters into more inputs than they are by taking the numbers after the decimal point and supplying them as separate parameters, this breaks the code, because what the validator receives is the following:
latitude=64.5151
longitude=0.5151
srid=-21.5454
I see this by setting a breakpoint in lib/python3.9/site-packages/werkzeug/routing/matcher.py before the line in the stack trace. Printing vars() there gives this:
{'self': <werkzeug.routing.matcher.StateMachineMatcher object at 0x7f98f57e5850>, 'domain': '', 'path': '/v1/lat/64.5151/long/-21.5454/srid/4326', 'rv': (<Rule '/v1/lat/<latitude>/long/<longitude>/srid/<srid>' (GET, HEAD, OPTIONS) -> /v1.test_controller_test_coords>, ['64.5151', '.5151', '-21.5454', '.5454', '4326']), 'rule': <Rule '/v1/lat/<latitude>/long/<longitude>/srid/<srid>' (GET, HEAD, OPTIONS) -> /v1.test_controller_test_coords>, 'values': ['64.5151', '.5151', '-21.5454', '.5454', '4326'], 'result': {}, 'name': 'latitude', 'value': '64.5151', '_match': <function StateMachineMatcher.match.<locals>._match at 0x7f98f3c01b80>, 'have_match_for': set(), 'websocket_mismatch': False, 'method': 'GET', 'websocket': False}
Notice ['64.5151', '.5151', '-21.5454', '.5454', '4326'], these are the path parameters the validator/controller is receiving. Somehow the .5151 and .5454 are added as parameters messing everything up.
Pressing continue prints the same thing, but with longitude as the value above
{'self': <werkzeug.routing.matcher.StateMachineMatcher object at 0x7f98f57e5850>, 'domain': '', 'path': '/v1/lat/64.5151/long/-21.5454/srid/4326', 'rv': (<Rule '/v1/lat/<latitude>/long/<longitude>/srid/<srid>' (GET, HEAD, OPTIONS) -> /v1.test_controller_test_coords>, ['64.5151', '.5151', '-21.5454', '.5454', '4326']), 'rule': <Rule '/v1/lat/<latitude>/long/<longitude>/srid/<srid>' (GET, HEAD, OPTIONS) -> /v1.test_controller_test_coords>, 'values': ['64.5151', '.5151', '-21.5454', '.5454', '4326'], 'result': {'latitude': 64.5151}, 'name': 'longitude', 'value': '.5151', '_match': <function StateMachineMatcher.match.<locals>._match at 0x7f98f3c01b80>, 'have_match_for': set(), 'websocket_mismatch': False, 'method': 'GET', 'websocket': False}
And continue again gives the srid value above
{'self': <werkzeug.routing.matcher.StateMachineMatcher object at 0x7f98f57e5850>, 'domain': '', 'path': '/v1/lat/64.5151/long/-21.5454/srid/4326', 'rv': (<Rule '/v1/lat/<latitude>/long/<longitude>/srid/<srid>' (GET, HEAD, OPTIONS) -> /v1.test_controller_test_coords>, ['64.5151', '.5151', '-21.5454', '.5454', '4326']), 'rule': <Rule '/v1/lat/<latitude>/long/<longitude>/srid/<srid>' (GET, HEAD, OPTIONS) -> /v1.test_controller_test_coords>, 'values': ['64.5151', '.5151', '-21.5454', '.5454', '4326'], 'result': {'latitude': 64.5151, 'longitude': 0.5151}, 'name': 'srid', 'value': '-21.5454', '_match': <function StateMachineMatcher.match.<locals>._match at 0x7f98f3c01b80>, 'have_match_for': set(), 'websocket_mismatch': False, 'method': 'GET', 'websocket': False}
Output of the commands:
python --version
Python 3.9.2pip show connexion | grep "^Version\:"
Version: 2.14.0
(this is how I use connexion in pipfile: connexion = {version = "==2.14.0", extras = ["swagger-ui"]})