Package: pydantic-compat
pydantic-compatMotivationPydantic 2 was a major release that completely changed the pydantic API.For applications, this is not a big deal, as they can pin to whatever version of
pydantic they need. But for libraries that want to exist in a broader
environment, pinning to a specific version of pydantic is not always an option
(as it limits the ability to co-exist with other libraries).This package provides (unofficial) compatibility mixins and function adaptors for pydantic
v1-v2 cross compatibility. It allows you to use either v1 or v2 API names,
regardless of the pydantic version installed. (Prefer using v2 names when possible).Tests are run on Pydantic v1.8 and upThe API conversion is not exhaustive, but suffices for many of the use cases
I have come across. It is in use by the following libraries:ome-typespsygnalapp-modeluseq-schemaFeel free to open an issue or PR if you find it useful, but lacking features
you need.What does it do?Not much! :joy:Mostly it serves to translate names from one API to another. It backports
the v2 API to v1 (so you can v2 names in a pydantic1 runtime),
and forwards the v1 API to v2 (so you can use v1 names in a v2 runtime
without deprecation warnings).While pydantic2 does offer deprecated access to the v1 API, if you explicitly
wish to support pydantic1 without your users seeing deprecation warnings,
then you need to do a lot of name adaptation depending on the runtime
pydantic version. This package does that for you.It doesnotdo any significantly complex translation of API logic.
For custom types, you will still likely need to add class methods to
support both versions of pydantic.It also does not prevent you from needing to know a what's changing
under the hood in pydantic 2. You should be running tests on both
versions of pydantic to ensure your library works as expected. This
library just makes it much easier to support both versions in a single
codebase without a lot of ugly conditionals and boilerplate.UsagefrompydanticimportBaseModelfrompydantic_compatimportPydanticCompatMixinfrompydantic_compatimportfield_validator# or 'validator'frompydantic_compatimportmodel_validator# or 'root_validator'classMyModel(PydanticCompatMixin,BaseModel):x:inty:int=2# prefer v2 dict, but v1 class Config is supportedmodel_config={'frozen':True}@field_validator('x',mode='after')def_check_x(cls,v):ifv!=42:raiseValueError("That's not the answer!")returnv@model_validator('x',mode='after')def_check_x(cls,v:MyModel):# ...returnvYou can now use the following attributes and methods regardless of the
pydantic version installed (without deprecation warnings):v1 namev2 nameobj.dict()obj.model_dump()obj.json()obj.model_dump_json()obj.copy()obj.model_copy()Model.constructModel.model_constructModel.schemaModel.model_json_schemaModel.validateModel.model_validateModel.parse_objModel.model_validateModel.parse_rawModel.model_validate_jsonModel.update_forward_refsModel.model_rebuildModel.__fields__Model.model_fieldsModel.__fields_set__Model.model_fields_setFieldnotespydantic_compat.Fieldwill remove outdated fields (const) and translate
fields with new names:v1 namev2 namemin_itemsmin_lengthmax_itemsmax_lengthregexpatternallow_mutationnot frozenmetadatajson_schema_extraDon't usevar = Field(..., const='val'), usevar: Literal['val'] = 'val'it works in both v1 and v2No attempt is made to convert between v1'sunique_itemsand v2'sSet[]semantics. Seehttps://github.com/pydantic/pydantic-core/issues/296for
discussion.API rulesboth V1 and V2 names may be used (regardless of pydantic version), but
usage of V2 names are strongly recommended.But the API must match the pydantic version matching the name you are using.
For example, if you are usingpydantic_compat.field_validatorthen the
signature must match the pydantic (v2)field_validatorsignature (regardless)
of the pydantic version installed. Similarly, if you choose to usepydantic_compat.validatorthen the signature must match the pydantic
(v1)validatorsignature.Notable differencesBaseModel.__fields__in v1 is a dict of{'field_name' -> ModelField}whereas in v2BaseModel.model_fieldsis a dict of{'field_name' -> FieldInfo}.FieldInfois a much simpler object that ModelField, so it is
difficult to directly support complicated v1 usage of__fields__.pydantic-compatsimply provides a name addaptor that lets you access many of
the attributes you may have accessed onModelFieldin v1 while operating in
a v2 world, butModelFieldmethods will not be made available. You'll need
to update your usage accordingly.in V2,pydantic.model_validator(..., mode='after')passes a modelinstanceto the validator function, whereaspydantic.v1.root_validator(..., pre=False)passes a dict of{'field_name' -> validated_value}to the
validator function. In pydantic-compat, both decorators follow the semantics
of their corresponding pydantic versions,butroot_validatorgains
parameterconstruct_object: bool=Falsethat matches themodel_validatorbehavior (only whenmode=='after'). If you want that behavior though, prefer
usingmodel_validatordirectly.TODO:Serialization decorators