Coverage for src/dirschema/json/handler_pydantic.py: 100%

23 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-12-07 09:34 +0000

1"""Minimal handler for using Pydantic models.""" 

2 

3from typing import Any, Dict, List, Optional, Type 

4 

5from pydantic import BaseModel, ValidationError 

6 

7from .handler import ValidationHandler 

8 

9 

10class PydanticHandler(ValidationHandler): 

11 """Validation handler using `parse_obj` of pydantic models instead of JSON Schema. 

12 

13 Can serve as a simple template for other handlers, or be subclassed 

14 to properly register your own models and used from your unique entry-point. 

15 

16 In principle, you can also override/add to the `MODELS` of this class 

17 programmatically, but then you must accept the following disadvantages: 

18 

19 * your dirschema using this handler cannot be checked from the CLI 

20 * your models are registered "globally", which might lead to collisions 

21 """ 

22 

23 MODELS: Dict[str, Type[BaseModel]] = {} 

24 

25 @classmethod 

26 def validate_json(cls, metadata: Any, args: str) -> Dict[str, List[str]]: 

27 """See [dirschema.json.handler.ValidationHandler.validate_json][].""" 

28 model: Optional[Type[BaseModel]] = cls.MODELS.get(args) 

29 if model is None: 

30 raise ValueError(f"Unknown pydantic model: '{args}'") 

31 if not issubclass(model, BaseModel): 

32 raise ValueError(f"Invalid pydantic model: '{args}'") 

33 try: 

34 model.parse_obj(metadata) 

35 except ValidationError as e: 

36 errs: Dict[str, List[str]] = {} 

37 for verr in e.errors(): 

38 key = "/" + "/".join(map(str, verr["loc"])) 

39 if key not in errs: 

40 errs[key] = [] 

41 errs[key].append(verr["msg"]) 

42 return errs 

43 return {}