7

According to the docs:

allow_mutation

whether or not models are faux-immutable, i.e. whether setattr is allowed (default: True)

Well I have a class :

class MyModel(BaseModel):

    field1:int

    class Config:
        allow_mutation = True

If I try to add a field dynamically :

model1 = MyModel(field1=1)
model1.field2 = 2

And I get this error :

  File "pydantic/main.py", line 347, in pydantic.main.BaseModel.__setattr__
ValueError: "MyModel" object has no field "field2"

Obviously, using setattr method will lead to the same error.

setattr(model1, 'field2', 2)

Output:

  File "pydantic/main.py", line 347, in pydantic.main.BaseModel.__setattr__
ValueError: "MyModel" object has no field "field2"

What did I miss here ?

jossefaz
  • 3,312
  • 4
  • 17
  • 40
  • Shouldn't the `setattr` call be on `model1` not `field2`, i.e., `setattr(model1, 'field2', 2)` ? – Josh Clark May 02 '22 at 14:02
  • typo in the question : fixed ! Thanks @JoshClark. Issue still here of course – jossefaz May 02 '22 at 14:18
  • is that setattr allowed on **existing** fields? ie field1, not field2. Try setting it to false, creating an instance and then setting field1 again on the instance. Thats likely what it controls rather than adding **arbitrary** attrs. – JL Peyret May 02 '22 at 15:22
  • @JLPeyret Does that mean that creating new fields on the fly is not possible ? – jossefaz May 02 '22 at 15:38
  • If what I suggest is correct, then yes it probably means that. I use pydantic extensively but not yet very in very complex ways. But it does not seem very intended to work with dynamic code, something I otherwise do a lot. What about a `dynvars : dict[str,Any] = field(factory=dict)` not sure about the factory syntax and mutating with extra random fields? – JL Peyret May 02 '22 at 15:42
  • @JLPeyret I finally found a kind of workaround. I posted it as an own answer. let me know your opinion about it if you can. – jossefaz May 02 '22 at 21:30

2 Answers2

6

You can use the Config object within the class and set the extra attribute to "allow" or use it as extra=Extra.allow kwargs when declaring the model

Example from the docs :

from pydantic import BaseModel, ValidationError, Extra


class Model(BaseModel, extra=Extra.forbid):
    a: str


try:
    Model(a='spam', b='oh no')
except ValidationError as e:
    print(e)
    """
    1 validation error for Model
    b
      extra fields not permitted (type=value_error.extra)
    """
jossefaz
  • 3,312
  • 4
  • 17
  • 40
Kwibus
  • 76
  • 1
  • 2
  • 5
    I find it a little bit bizarre that the opposite of the solution is demonstrated in the answer. Just for the record, you'll want to use `class Model(BaseModel, extra=Extra.allow):` and then keyword arguments to the constructor will be instantiated as attributes. – NeilG Feb 23 '23 at 08:16
0

Putting an example using extra.allow that answers the question asked.

from pydantic import BaseModel, ValidationError, Extra


class Model(BaseModel, extra=Extra.allow):
    a: str

my_model = Model(a="1")
my_model.b = "2"
# Model(a='1', b='2')
Kieran101
  • 565
  • 5
  • 18
  • :How does your answer add a value to the existing (and accepted one) ? seems to be the same... – jossefaz Aug 17 '23 at 07:22
  • It uses `Extra.allow` instead of `Extra.forbid`. @Kwibus had the right suggestion, but the example he offers uses the opposite case. Refer to @NeilG's comment. – Kieran101 Aug 21 '23 at 03:20
  • I suppose I could have suggested an edit to the existing answer instead – Kieran101 Aug 21 '23 at 03:22