flask-parameter-validation icon indicating copy to clipboard operation
flask-parameter-validation copied to clipboard

Optional and Union types break automatic API Docs

Open JoshieJay opened this issue 1 year ago • 3 comments

Using an Optional or Union type with the @ValidateParameters decorator works for validation purposes, but it causes a 500 error when accessing the /docs route.

It looks like it may be this function that is causing the issue.

def get_arg_type_hint(fdocs, arg_name): """ Extract the type hint for a specific argument. """ arg_type = fdocs["argspec"].annotations[arg_name] if hasattr(arg_type, "__args__"): return ( f"{arg_type.__name__}[{', '.join([a.__name__ for a in arg_type.__args__])}]" ) return arg_type.__name__

Specifically the arg_type.__name__ seems to not exist for Optional and Union types.

It looks like there is a note about Optional parameters in 2.3.0 (https://github.com/Ge0rg3/flask-parameter-validation/releases/tag/v2.3.0), but I think this may just be for validation.

JoshieJay avatar Sep 06 '24 14:09 JoshieJay

Thanks for reporting this! I'll look into it when I get home :)

smt5541 avatar Sep 06 '24 18:09 smt5541

Sorry, this weekend was busier than expected - I'll take a look sometime this week

smt5541 avatar Sep 09 '24 19:09 smt5541

Apologies again for the delay, finally got a chance to look at this today and am having issues reproducing the issue on Python 3.12: pip freeze output:

asgiref==3.8.1
attrs==24.2.0
blinker==1.8.2
click==8.1.7
Flask==3.0.3
Flask-Parameter-Validation==2.4.0
itsdangerous==2.2.0
Jinja2==3.1.4
jsonschema==4.23.0
jsonschema-specifications==2023.12.1
MarkupSafe==2.1.5
python-dateutil==2.9.0.post0
referencing==0.35.1
rpds-py==0.20.0
six==1.16.0
Werkzeug==3.0.4

Code Tested:

from flask import Flask
from flask_parameter_validation import ValidateParameters
from flask_parameter_validation.parameter_types import Query, Json
from flask_parameter_validation.docs_blueprint import docs_blueprint
from typing import Optional, Union

app = Flask(__name__)


app.register_blueprint(docs_blueprint)

@app.route("/")
@ValidateParameters()
def hello_world():
  return "Hello, World!"

@app.get("/optional")
@ValidateParameters()
def optional(q: Optional[int] = Query()):
  return f"<strong>{q}</strong>"

@app.post("/union")
@ValidateParameters()
def union(j: Union[int, float] = Json()):
  return f"<strong>{j}</strong>"

Resulting documentation: image

smt5541 avatar Oct 04 '24 21:10 smt5541