11"""JSON API schemas builder class."""
2- from copy import deepcopy
32from dataclasses import dataclass
43from typing import (
54 Any ,
87 Iterable ,
98 List ,
109 Optional ,
11- Set ,
1210 Tuple ,
1311 Type ,
1412 TypeVar ,
1513 Union ,
1614)
1715
1816import pydantic
19- from pydantic import (
20- BaseConfig ,
21- root_validator ,
22- validator ,
23- )
17+ from pydantic import BaseConfig
2418from pydantic import BaseModel as PydanticBaseModel
25- from pydantic .class_validators import (
26- extract_root_validators ,
27- extract_validators ,
28- inherit_validators ,
29- )
30- from pydantic .fields import FieldInfo , ModelField , Validator
31- from pydantic .utils import unique_list
19+ from pydantic .fields import FieldInfo , ModelField
3220
3321from fastapi_jsonapi .data_typing import TypeSchema
3422from fastapi_jsonapi .schema import (
4533)
4634from fastapi_jsonapi .schema_base import BaseModel , Field , RelationshipInfo , registry
4735from fastapi_jsonapi .splitter import SPLIT_REL
36+ from fastapi_jsonapi .validation_utils import (
37+ extract_field_validators ,
38+ extract_validators ,
39+ )
4840
4941JSON_API_RESPONSE_TYPE = Dict [Union [int , str ], Dict [str , Any ]]
5042
@@ -301,7 +293,7 @@ def _get_info_from_schema_for_building(
301293 # works both for to-one and to-many
302294 included_schemas .append ((name , field .type_ , relationship .resource_type ))
303295 elif name == "id" :
304- id_validators = self . _extract_field_validators (
296+ id_validators = extract_field_validators (
305297 schema ,
306298 include_for_field_names = {"id" },
307299 )
@@ -323,7 +315,7 @@ class ConfigOrmMode(BaseConfig):
323315 f"{ base_name } AttributesJSONAPI" ,
324316 ** attributes_schema_fields ,
325317 __config__ = ConfigOrmMode ,
326- __validators__ = self . _extract_validators (schema , exclude_for_field_names = {"id" }),
318+ __validators__ = extract_validators (schema , exclude_for_field_names = {"id" }),
327319 )
328320
329321 relationships_schema = pydantic .create_model (
@@ -391,110 +383,6 @@ def create_relationship_data_schema(
391383 self .relationship_schema_cache [cache_key ] = relationship_data_schema
392384 return relationship_data_schema
393385
394- def _extract_root_validators (self , model : Type [BaseModel ]) -> Dict [str , Callable ]:
395- pre_rv_new , post_rv_new = extract_root_validators (model .__dict__ )
396- pre_root_validators = unique_list (
397- model .__pre_root_validators__ + pre_rv_new ,
398- name_factory = lambda v : v .__name__ ,
399- )
400- post_root_validators = unique_list (
401- model .__post_root_validators__ + post_rv_new ,
402- name_factory = lambda skip_on_failure_and_v : skip_on_failure_and_v [1 ].__name__ ,
403- )
404-
405- result_validators = {}
406-
407- for validator_func in pre_root_validators :
408- result_validators [validator_func .__name__ ] = root_validator (
409- pre = True ,
410- allow_reuse = True ,
411- )(validator_func )
412-
413- for skip_on_failure , validator_func in post_root_validators :
414- result_validators [validator_func .__name__ ] = root_validator (
415- allow_reuse = True ,
416- skip_on_failure = skip_on_failure ,
417- )(validator_func )
418-
419- return result_validators
420-
421- def _deduplicate_field_validators (self , validators : dict ) -> dict :
422- result_validators = {}
423-
424- for field_name , field_validators in validators .items ():
425- result_validators [field_name ] = list (
426- {
427- # override in definition order
428- field_validator .func .__name__ : field_validator
429- for field_validator in field_validators
430- }.values (),
431- )
432-
433- return result_validators
434-
435- def _extract_field_validators (
436- self ,
437- model : Type [BaseModel ],
438- * ,
439- include_for_field_names : Set [str ] = None ,
440- exclude_for_field_names : Set [str ] = None ,
441- ):
442- validators = inherit_validators (
443- extract_validators (model .__dict__ ),
444- deepcopy (model .__validators__ ),
445- )
446- validators = self ._deduplicate_field_validators (validators )
447- validator_origin_param_keys = (
448- "pre" ,
449- "each_item" ,
450- "always" ,
451- "check_fields" ,
452- )
453-
454- exclude_for_field_names = exclude_for_field_names or set ()
455-
456- if include_for_field_names and exclude_for_field_names :
457- exclude_for_field_names = include_for_field_names .difference (
458- exclude_for_field_names ,
459- )
460-
461- result_validators = {}
462- for field_name , field_validators in validators .items ():
463- if field_name in exclude_for_field_names :
464- continue
465-
466- if include_for_field_names and field_name not in include_for_field_names :
467- continue
468-
469- field_validator : Validator
470- for field_validator in field_validators :
471- validator_name = f"{ field_name } _{ field_validator .func .__name__ } _validator"
472- validator_params = {
473- # copy validator params
474- param_key : getattr (field_validator , param_key )
475- for param_key in validator_origin_param_keys
476- }
477- result_validators [validator_name ] = validator (
478- field_name ,
479- ** validator_params ,
480- allow_reuse = True ,
481- )(field_validator .func )
482-
483- return result_validators
484-
485- def _extract_validators (
486- self ,
487- model : Type [BaseModel ],
488- exclude_for_field_names : Set [str ] = None ,
489- ) -> Dict [str , Callable ]:
490- return {
491- ** self ._extract_field_validators (
492- model ,
493- exclude_for_field_names = exclude_for_field_names ,
494- ),
495- ** self ._extract_root_validators (model ),
496- }
497-
498386 def _build_jsonapi_object (
499387 self ,
500388 base_name : str ,
0 commit comments