FastAPI/pydantic: field_validator не учитывается при использовании пустого Depends() ⇐ Python
FastAPI/pydantic: field_validator не учитывается при использовании пустого Depends()
I am following Method 2 of this answer to be able to upload multiple files in combination with additional data using fastapi. It is working fine.
After starting to implement the handling of the additional data including validation using pydantic's BaseModel i am facing an issue:
My custom field_validator is working when using the model class directly but it is not working as expected, when using it via FastAPI and Depends().
The key point is that i want to use a python Enum and i want to be able to use the Enum's names in the additional data (query parameters). For this reason i am using a custom validator to only allow names which exist in the enum.
When i initialize the model manually, the validation works as expected:
from enum import Enum from pydantic import BaseModel, field_validator, ValidationInfo, ValidationError class VehicleSubSystems(Enum): A = "A Verbose" B = "B Verbose" class EvaluationArguments(BaseModel): vehicle_sub_system: VehicleSubSystems @field_validator("vehicle_sub_system", mode='before') @classmethod def validate_vehicle_sub_system(cls, vehicle_sub_system: str, _info: ValidationInfo) -> VehicleSubSystems: """ Allows using the enum names instead of the values """ try: return VehicleSubSystems[vehicle_sub_system] except KeyError: raise ValueError(f"Can not find vehicle subsystem '{vehicle_sub_system}'. " f"Allowed values: {[e.name for e in VehicleSubSystems]}") def test_validation_is_performed(): """ Test that the validation is performed """ EvaluationArguments(vehicle_sub_system="A") try: EvaluationArguments(vehicle_sub_system="DOES_NOT_EXIST") except ValidationError: print("Test passed") else: print("Test failed") if __name__ == '__main__': test_validation_is_performed() # prints "Test passed" as expected Combining this with the FastAPI application shows unexpected behavior: The field_validator is not considered. Instead the default behavior of the model class is used.
Server code:
import uvicorn from typing import List from fastapi import FastAPI, File, Depends, UploadFile app = FastAPI() def create_args(vehicle_sub_system: str): return EvaluationArguments(vehicle_sub_system=vehicle_sub_system) @app.post("/process-works") def process_works(files: List[UploadFile] = File(...), eval_args: EvaluationArguments = Depends(create_args)): return f"Got {len(files)} files and {eval_args}" @app.post("/process-fails") def process_fails(files: List[UploadFile] = File(...), eval_args: EvaluationArguments = Depends()): return f"Got {len(files)} files and {eval_args}" if __name__ == '__main__': uvicorn.run(app, host="0.0.0.0", port=8000) Client code:
import requests if __name__ == '__main__': url = 'http://127.0.0.1:8000' files = [('files', open('d:/temp/a.txt', 'rb')), ('files', open('d:/temp/b.txt', 'rb'))] params = {"vehicle_sub_system": "A"} print("Calling process-works") resp = requests.post(url=f"{url}/process-works", params=params, files=files) print(resp.json()) print("Calling process-fails") resp = requests.post(url=f"{url}/process-fails", params=params, files=files) print(resp.json()) # Output # Calling process-works # Got 2 files and vehicle_sub_system= # Calling process-fails # {'detail': [{'type': 'enum', 'loc': ['query', 'vehicle_sub_system'], 'msg': "Input should be 'A Verbose' or 'B Verbose'", 'input': 'A', 'ctx': {'expected': "'A Verbose' or 'B Verbose'"}}]} The process-works endpoint shows the expected behavior but only when using a separate dependency Depends(create_args) which mimics the direct usage of the model class.
The process-fails endpoint (using Depends()) shows the issue. I would expect that Depends() is just making FastAPI to call the init method of the model class and uses the validation as expected. But somehow it just ignores it.
I could not figure out why, perhaps somebody can explain what happens here and if there is a solution without the workaround?
Источник: https://stackoverflow.com/questions/780 ... ty-depends
I am following Method 2 of this answer to be able to upload multiple files in combination with additional data using fastapi. It is working fine.
After starting to implement the handling of the additional data including validation using pydantic's BaseModel i am facing an issue:
My custom field_validator is working when using the model class directly but it is not working as expected, when using it via FastAPI and Depends().
The key point is that i want to use a python Enum and i want to be able to use the Enum's names in the additional data (query parameters). For this reason i am using a custom validator to only allow names which exist in the enum.
When i initialize the model manually, the validation works as expected:
from enum import Enum from pydantic import BaseModel, field_validator, ValidationInfo, ValidationError class VehicleSubSystems(Enum): A = "A Verbose" B = "B Verbose" class EvaluationArguments(BaseModel): vehicle_sub_system: VehicleSubSystems @field_validator("vehicle_sub_system", mode='before') @classmethod def validate_vehicle_sub_system(cls, vehicle_sub_system: str, _info: ValidationInfo) -> VehicleSubSystems: """ Allows using the enum names instead of the values """ try: return VehicleSubSystems[vehicle_sub_system] except KeyError: raise ValueError(f"Can not find vehicle subsystem '{vehicle_sub_system}'. " f"Allowed values: {[e.name for e in VehicleSubSystems]}") def test_validation_is_performed(): """ Test that the validation is performed """ EvaluationArguments(vehicle_sub_system="A") try: EvaluationArguments(vehicle_sub_system="DOES_NOT_EXIST") except ValidationError: print("Test passed") else: print("Test failed") if __name__ == '__main__': test_validation_is_performed() # prints "Test passed" as expected Combining this with the FastAPI application shows unexpected behavior: The field_validator is not considered. Instead the default behavior of the model class is used.
Server code:
import uvicorn from typing import List from fastapi import FastAPI, File, Depends, UploadFile app = FastAPI() def create_args(vehicle_sub_system: str): return EvaluationArguments(vehicle_sub_system=vehicle_sub_system) @app.post("/process-works") def process_works(files: List[UploadFile] = File(...), eval_args: EvaluationArguments = Depends(create_args)): return f"Got {len(files)} files and {eval_args}" @app.post("/process-fails") def process_fails(files: List[UploadFile] = File(...), eval_args: EvaluationArguments = Depends()): return f"Got {len(files)} files and {eval_args}" if __name__ == '__main__': uvicorn.run(app, host="0.0.0.0", port=8000) Client code:
import requests if __name__ == '__main__': url = 'http://127.0.0.1:8000' files = [('files', open('d:/temp/a.txt', 'rb')), ('files', open('d:/temp/b.txt', 'rb'))] params = {"vehicle_sub_system": "A"} print("Calling process-works") resp = requests.post(url=f"{url}/process-works", params=params, files=files) print(resp.json()) print("Calling process-fails") resp = requests.post(url=f"{url}/process-fails", params=params, files=files) print(resp.json()) # Output # Calling process-works # Got 2 files and vehicle_sub_system= # Calling process-fails # {'detail': [{'type': 'enum', 'loc': ['query', 'vehicle_sub_system'], 'msg': "Input should be 'A Verbose' or 'B Verbose'", 'input': 'A', 'ctx': {'expected': "'A Verbose' or 'B Verbose'"}}]} The process-works endpoint shows the expected behavior but only when using a separate dependency Depends(create_args) which mimics the direct usage of the model class.
The process-fails endpoint (using Depends()) shows the issue. I would expect that Depends() is just making FastAPI to call the init method of the model class and uses the validation as expected. But somehow it just ignores it.
I could not figure out why, perhaps somebody can explain what happens here and if there is a solution without the workaround?
Источник: https://stackoverflow.com/questions/780 ... ty-depends
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
FastAPI/pydantic: field_validator не учитывается при использовании пустого Depends()
Anonymous » » в форуме Python - 0 Ответы
- 22 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Наследует help_text из django.db.models.Field в rest_framework.serializer.Field
Anonymous » » в форуме Python - 0 Ответы
- 70 Просмотры
-
Последнее сообщение Anonymous
-