question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Class attributes starting with underscore do not support assignment

See original GitHub issue

Bug

For bugs/questions:

  • OS: macOS
  • Python version import sys; print(sys.version): 3.6.6
  • Pydantic version import pydantic; print(pydantic.VERSION): 0.14

In #184 it was suggested to use variables starting with the underscore, however this does not work. The last comment in #184 referred to the same problem, but it is technically a separate issue.

from pydantic import BaseModel
m = BaseModel()
m._foo = "bar"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/dmfigol/projects/my/public/simple-smartsheet/.venv/lib/python3.6/site-packages/pydantic/main.py", line 176, in __setattr__
    raise ValueError(f'"{self.__class__.__name__}" object has no field "{name}"')
ValueError: "BaseModel" object has no field "_foo"

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:13
  • Comments:48 (15 by maintainers)

github_iconTop GitHub Comments

41reactions
pdonoriocommented, Dec 7, 2019

Hello there, I use pydantic in FastAPI as well, and I use mongodb as database.

Mongo sets Identifiers as the field _id in collections/query outputs and handling those via Pydantic models is quite confusing because of this issue. Let me try to show what I do to ask if I’m doing something wrong; situations I’ve met with my use case

  1. when sending the id as output I have to create a Model with the alias as
class Foo(BaseModel):
    id: str = Field(..., alias='_id')
    ...

query = db.collection.find(...)
validated = Foo(**query).dict()
# where validated = {'id': MONGO_HASH, ...}
# send validated as response

Note: if I’d want to send the id like mongo does (if my API are used by another service that deals with queries and mongo for example) I need to use

validated = Foo(**query).dict(by_alias=True)
# where validated = {'_id': MONGO_HASH, ...}
  1. when storing a PUT in the database the above require the input to be using id instead of _id like:
data = read_from_source(...)
# data = {'id': EXISTING_MONGO_HASH, ...}
db.collection.update(Foo(**data).dict(by_alias=True))

but if some other service is sending me raw data I would get the _id in input so I need to change the model to

class Foo(BaseModel):
    id: str = Field(..., alias='_id')
    ...
    class Config:
        allow_population_by_field_name = True

otherwise I get a validation error


There are other situations that I can’t recall well enough to show with code, but in general I’m currently forced by pydantic on taking care of these differences since the underscores are not accepted. I wouldn’t use the id translation at all, I’d go with _id always - because I’m risking non deterministic behaviour in wrapper methods for all models in the codebase and in the responses.

Hope this helps to reason on it, but thanks for this awesome library!

37reactions
bartekbrakcommented, Jun 26, 2019

I read the above but saw no explanation for this limitation. From brief study of the source code I could not determine any danger in sunder fields.

This check is introduced in the first commit ever a8e844da and a check added in f9cf6b42 but no explanation given in commit messages.

Python itself by design does not enforce any special meaning to sunder and dunder fields - the “we are all consenting adults here” approach. I am used to a convention of marking fields private-like with sunder.

Using aliases is clumsy. I use Pydantic to save code lines and make code more readable. I would rather not add this magic. Also this prevents me from doing arguably dirty trick of having both _response and response (processed response).

I would very much like to know the motivation or have this restriction lifted.

Still, I adore Pydantic, thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Class attributes starting with underscore do not support ...
I need to load the raw value that arrives and keep it in a private member (something prefixed with an underscore _ )....
Read more >
When I run this program in PyCharm I get the following errors
Attributes with names starting with double underscores are considered "private", and not accessible from child classes.
Read more >
Customizing what happens when you assign an attribute
Want to customize what happens when you assign to a specific attribute on your class instances? You can use a property with a...
Read more >
Role of Underscore(_) in Python Tutorial - DataCamp
Ignoring means assigning the values to special variable underscore(_). We're assigning the values to underscore(_) given not using that in future code.
Read more >
Understanding the underscore( _ ) of Python - HackerNoon
Anything with this convention are ignored in from module import * . However, of course, Python does not supports truly private, so we...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found