Comments (2)
It's a bit nasty but I've created a model which allows us to defer the validation until we want to call it:
from pydantic import BaseModel, validate_model, ValidationError
class SomeModel(BaseModel):
name: str
class Config:
validate_assignment = False
extra = "forbid"
def __init__(self, name: str):
values, fields_set, validation_error = validate_model(self.__class__, {})
object.__setattr__(self, "__dict__", values)
object.__setattr__(self, "__fields_set__", fields_set)
self._init_private_attributes()
self.name = name
def validate(self):
values, fields_set, validation_error = validate_model(self.__class__, self.dict())
if validation_error:
raise validation_error
model = SomeModel(None)
model.validate()
I do not trust this code if we upgrade pydantic from the current version.
from csvcubed.
The following is a more robust approach using python's dataclasses combined with pydantic's version of them.
Upon validation, I use the python dataclasses functionality to convert the model to a dictionary. I pass these values into the same model wrapped with pydantic's dataclass annotation. I try to catch any validation error exceptions which are then passed back to the caller. If validation is successful, I copy all of the attributes from the pydantic class back to the model - pydantic coerces values to match the annotated datatype where possible.
The SomeModel
dataclass defined below is what I've used to test validation:
import dataclasses
from pydantic import BaseConfig
import pydantic
import pydantic.dataclasses
from dataclasses import dataclass, asdict
from typing import ClassVar, Dict, Type, List
from abc import ABC
from csvqb.models.validationerror import ValidationError
@dataclass
class ValidatedModel(ABC):
"""
ValidatedModel - an abstract base class to be inherited by models which want a `validate` method which verifies
that the model's attributes agree with the corresponding type annotations.
Uses pydantic under the hood, but rather than using pydantic's constructor validation approach, we delay
validation until the `validate` method is called.
"""
_map_class_to_pydantic_constructor: ClassVar[Dict[Type, Type]] = dict()
"""_map_class_to_pydantic_constructor - Cache of pydantic constructor corresponding to a given class."""
class Config(BaseConfig):
"""pydantic Configuration - see https://pydantic-docs.helpmanual.io/usage/model_config/"""
extra = "forbid"
@classmethod
def _get_pydantic_constructor(cls) -> Type:
if cls not in ValidatedModel._map_class_to_pydantic_constructor:
ValidatedModel._map_class_to_pydantic_constructor[cls] = pydantic.dataclasses.dataclass(cls)
return ValidatedModel._map_class_to_pydantic_constructor[cls]
def as_dict(self) -> dict:
"""Use python dataclasses method to return this model as a dictionary."""
return asdict(self)
def validate(self) -> List[ValidationError]:
"""
Validate this model using pydantic.
Checks that all model attributes match the expected annotated data type. **Coerces values** where possible.
"""
pydantic_class_constructor = self.__class__._get_pydantic_constructor()
try:
validated_model = pydantic_class_constructor(**self.as_dict())
except pydantic.ValidationError as error:
return [ValidationError(f"{e['loc']} - {e['msg']}") for e in error.errors()]
# Update this model's values with pydantic's coerced values
for field in dataclasses.fields(self):
setattr(self, field.name, getattr(validated_model, field.name))
# there are no validation errors
return []
@dataclass
class SomeModel(ValidatedModel):
name: str
age: int
model = SomeModel(name="Jim", age="20")
print([str(e) for e in model.validate()])
print(model)
in this example, the age is coerced into an int yielding the output:
[]
SomeModel(name='Jim', age=20)
Example with errors:
model = SomeModel(name=None, age=20)
print([str(e) for e in model.validate()])
print(model)
["ValidationError(('name',) - none is not an allowed value)"]
SomeModel(name=None, age=20)
from csvcubed.
Related Issues (20)
- User Feedback Prompt (build complete review request)
- attribute describes observations #583 revisit
- Get the CSV-W be a dcat:distributionOf a dcat:DataSet
- Fix the dependabot stuff
- User Feedback Prompt (error documentation review request)
- Adopt a gov-style mkdoc template
- Allow running docker on windows for csvw-check behave tests
- Fix developer docs link on csvcubed pypi page
- Attribute value codelists - enhancements
- Include column title in logger messages
- Attribute value codelists - feature flag removal
- Replacing jsonschema.RefResolver with referencing.Registry
- analyst function observation status template HOT 1
- Using dcat:Distribution for ConceptSchemes
- Using old version of csvcubed with new $schema HOT 1
- Implement pandas v2.1.1
- Observation column named Value
- csvcubed-models Distribution class
- csvcubed v1.0
- Implement GitHub environments for deployment
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from csvcubed.