Source code for ch_api.types.base
"""Base Pydantic model for Companies House API types.
Extends Pydantic's BaseModel with field name normalization for API responses.
See Also:
https://docs.pydantic.dev/latest/
"""
import typing
import pydantic
from . import settings
[docs]
class BaseModel(pydantic.BaseModel):
"""Base Pydantic model for Companies House API responses.
Automatically normalizes field names to lowercase for consistency.
Inherits from this class for all API response models.
"""
model_config = pydantic.ConfigDict(
extra=settings.model_validate_extra,
)
[docs]
@classmethod
def model_validate( # type: ignore[override]
cls, data: typing.Any, **kwargs: typing.Any
) -> "BaseModel":
"""Validate and create model instance from API response data.
This method extends Pydantic's validation to handle Companies House API
response patterns including field name normalization and filtering of
deprecated/unused fields.
The method performs the following transformations:
1. **Field name normalization**: Converts all field names to lowercase
2. **Whitespace trimming**: Removes leading/trailing whitespace from field names
3. **Deprecated field filtering**: Removes fields marked as ``[notinuse]``
Parameters
----------
data : Any
Raw data from API response, typically a dictionary with field names
that may use mixed case (e.g., ``CompanyName``, ``company_number``).
Also supports non-dict data, which is passed directly to Pydantic's
validation without modification.
Returns
-------
BaseModel
A validated model instance with normalized field names and
deprecated fields removed.
Example
-------
Validate API response with mixed-case field names::
>>> from ch_api.types.base import BaseModel
>>> # The BaseModel normalizes field names automatically
>>> # Example: API returns {"CompanyNumber": "..."} but model expects company_number
>>> # This is handled transparently by model_validate()
>>> #
>>> # Deprecated fields marked with [notinuse] are automatically filtered:
>>> # Example: {"OldField[notinuse]": "value"} -> automatically excluded
Note
----
This method is automatically called by Pydantic when deserializing
JSON or dict data into the model. You typically don't need to call
this method directly unless you're doing custom serialization/deserialization.
See Also
--------
pydantic.BaseModel.model_validate : Parent Pydantic validation method
"""
if isinstance(data, dict):
updated_data = {}
for key, value in data.items():
if isinstance(key, str):
key = key.lower().strip()
if "[notinuse]" in key:
# Skip fields that are marked as not in use
continue
updated_data[key] = value
data = updated_data
return super().model_validate(data)