Is it bad practice to include non-validating methods in a pydantic model?

Question:

I’m using pydantic 1.3 to validate models for an API I am writing.

Is it common/good practice to include arbitrary methods in a class that inherits from pydantic.BaseModel?

I need some helper methods associated with the objects and I am trying to decide whether I need a "handler" class. These models are being converted to JSON and sent to a restful service that I am also writing.

My model looks like this:

class Foo(pydantic.BaseModel):
    name: str
    bar: int
    baz: int

Is it poor practice to do something like:

class Foo(pydantic.BaseModel):
    name: str
    bar: int
    baz: int

    def add_one(self):
        self.bar += 1

It makes some sense to me, but I can’t find an example of anyone doing this.

Asked By: ccred

||

Answers:

Yes, it’s fine. We should probably document it.

The only problem comes when you have a field name which conflicts with the method, but that’s not a problem if you know what your data looks like. Also, it’s possible to over object orient your code, but you’re a long way from that.

Answered By: SColvin

I have a similar question –

the following works well in the way defined above:

from pydantic import BaseModel
import pathlib
import typing

class BaseModel(BaseModel):
    def file(self: typing.Type[BaseModel], path: pathlib.Path, **json_kwargs):
        """
        this is a method that is added to the pydantic BaseModel within AutoUi using
        "setattr".

        Example:
            ```setattr(model, 'file', file)```

        Args:
            self (pydantic.BaseModel): instance
            path (pathlib.Path): to write file to
        """
        if "indent" not in json_kwargs.keys():
            json_kwargs.update({"indent": 4})
        path.write_text(self.json(**json_kwargs), encoding="utf-8")


class DataFrameCols(BaseModel):
    string: str = "string"
    integer: int = 1
    floater: float = 1.2
    something_else: float = 1


t = DataFrameCols()
t.file(pathlib.Path("test.json"))
# file successfully saved

but I’d like to add the method to the class on-the-fly.
e.g.

def foo():
    print("foo")


class A:
    def bar(self):
        print("bar")


def barFighters(self):
    print("barFighters")


a = A()
a.barFighters = types.MethodType(barFighters, a)

a.barFighters()

>>> "barFighters"

if I try and do this though, I get a ValueError…

from pydantic import BaseModel
​
​
class DataFrameCols(BaseModel):
    string: str = Field("string", aui_column_width=100)
    integer: int = Field(1, aui_column_width=80)
    floater: float = Field(3.1415, aui_column_width=70, aui_sig_fig=3)
    something_else: float = Field(324, aui_column_width=100)
    
def file(self: typing.Type[BaseModel], path: pathlib.Path, **json_kwargs):
    """
    this is a method that is added to the pydantic BaseModel within AutoUi using
    "setattr".
​
    Example:
        ```setattr(model, 'file', file)```
​
    Args:
        self (pydantic.BaseModel): instance
        path (pathlib.Path): to write file to
    """
    if "indent" not in json_kwargs.keys():
        json_kwargs.update({"indent": 4})
    path.write_text(self.json(**json_kwargs), encoding="utf-8")
​
t = DataFrameCols()
t.file = types.MethodType(file, t)
​
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [50], in <cell line: 27>()
     24     path.write_text(self.json(**json_kwargs), encoding="utf-8")
     26 t = DataFrameCols()
---> 27 t.file = types.MethodType(file, t)

File ~/miniconda3/envs/ipyautoui-dev/lib/python3.9/site-packages/pydantic/main.py:347, in pydantic.main.BaseModel.__setattr__()

ValueError: "DataFrameCols" object has no field "file"

is there a way around this?

many thanks

Answered By: John—