def add_fields(cls, **field_definitions: Tuple[str, Any]) -> None: """Add fields to the model. Adapted from here : https://github.com/samuelcolvin/pydantic/issues/1937#issuecomment-695313040 """ new_fields: Dict[str, ModelField] = {} new_annotations: Dict[str, Optional[type]] = {} validators = None for f_name, f_def in field_definitions.items(): f_annotation, f_value = f_def if cls.__vg__: validators = cls.__vg__.get_validators(f_name) new_fields[f_name] = ModelField.infer( name=f_name, value=f_value, annotation=f_annotation, class_validators=validators, config=cls.__config__, ) cls.__fields__.update(new_fields) cls.__annotations__.update(new_annotations)
def add_fields(cls, **field_definitions: Any): """ This class lets a caller define new custom fields in the container model by dynamically inserting fields inplace, so that when the service parses an incoming container that container can be parsed with the new fields in mind, applying validation, etc. """ new_fields: Dict[str, ModelField] = {} new_annotations: Dict[str, Optional[type]] = {} for f_name, f_annotation in field_definitions.items(): new_annotations[f_name] = f_annotation new_fields[f_name] = ModelField.infer(name=f_name, value=None, annotation=f_annotation, class_validators=None, config=cls.__config__) cls.__fields__.update(new_fields) cls.__annotations__.update(new_annotations)
def __new__(mcs, name, bases, namespace, **kwargs): from pydantic.fields import Undefined from pydantic.class_validators import extract_validators, inherit_validators from pydantic.types import PyObject from pydantic.typing import is_classvar, resolve_annotations from pydantic.utils import lenient_issubclass, validate_field_name from pydantic.main import inherit_config, prepare_config, UNTOUCHED_TYPES fields: Dict[str, ModelField] = {} config = BaseConfig validators: Dict[str, List[Validator]] = {} for base in reversed(bases): if issubclass(base, AbstractCheckedSession) and base != AbstractCheckedSession: config = inherit_config(base.__config__, config) fields.update(deepcopy(base.__fields__)) validators = inherit_validators(base.__validators__, validators) config = inherit_config(namespace.get('Config'), config) validators = inherit_validators(extract_validators(namespace), validators) # update fields inherited from base classes for field in fields.values(): field.set_config(config) extra_validators = validators.get(field.name, []) if extra_validators: field.class_validators.update(extra_validators) # re-run prepare to add extra validators field.populate_validators() prepare_config(config, name) # extract and build fields class_vars = set() if (namespace.get('__module__'), namespace.get('__qualname__')) != \ ('larray.core.checked', 'CheckedSession'): untouched_types = UNTOUCHED_TYPES + config.keep_untouched # annotation only fields need to come first in fields annotations = resolve_annotations(namespace.get('__annotations__', {}), namespace.get('__module__', None)) for ann_name, ann_type in annotations.items(): if is_classvar(ann_type): class_vars.add(ann_name) elif not ann_name.startswith('_'): validate_field_name(bases, ann_name) value = namespace.get(ann_name, Undefined) if (isinstance(value, untouched_types) and ann_type != PyObject and not lenient_issubclass(getattr(ann_type, '__origin__', None), Type)): continue fields[ann_name] = ModelField.infer(name=ann_name, value=value, annotation=ann_type, class_validators=validators.get(ann_name, []), config=config) for var_name, value in namespace.items(): # 'var_name not in annotations' because namespace.items() contains annotated fields # with default values # 'var_name not in class_vars' to avoid to update a field if it was redeclared (by mistake) if (var_name not in annotations and not var_name.startswith('_') and not isinstance(value, untouched_types) and var_name not in class_vars): validate_field_name(bases, var_name) # the method ModelField.infer() fails to infer the type of Group objects # (which are interpreted as ndarray objects) annotation = type(value) if isinstance(value, Group) else annotations.get(var_name) inferred = ModelField.infer(name=var_name, value=value, annotation=annotation, class_validators=validators.get(var_name, []), config=config) if var_name in fields and inferred.type_ != fields[var_name].type_: raise TypeError(f'The type of {name}.{var_name} differs from the new default value; ' f'if you wish to change the type of this field, please use a type ' f'annotation') fields[var_name] = inferred new_namespace = { '__config__': config, '__fields__': fields, '__field_defaults__': {n: f.default for n, f in fields.items() if not f.required}, '__validators__': validators, **{n: v for n, v in namespace.items() if n not in fields}, } return super().__new__(mcs, name, bases, new_namespace, **kwargs)