The underscore_attrs_are_private config flag turns __doc__ attribute into a ModelPrivateAttr #2090
Closed
Description
Checks
- I added a descriptive title to this issue
- I have searched (google, github) for similar issues and couldn't find anything
- I have read and followed the docs and still think this is a bug
Bug
Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())"
:
pydantic version: 1.7.2
pydantic compiled: False
install path: D:\dev\Miniconda3\envs\geoenv\Lib\site-packages\pydantic
python version: 3.8.6 | packaged by conda-forge | (default, Oct 7 2020, 18:22:52) [MSC v.1916 64 bit (AMD64)]
platform: Windows-10-10.0.19041-SP0
optional deps. installed: ['typing-extensions']
Pydantic v1.7 introduced the private attributes. But when the config flag underscore_attrs_are_private
is set to True
, the model's __doc__
attribute also becomes a private attribute. Example:
>>> from pydantic import BaseModel
>>> class MyModel(BaseModel):
... """MyModel docsting."""
... class Config:
... underscore_attrs_are_private = True
...
>>> MyModel.__doc__
<member '__doc__' of 'MyModel' objects>
My current workaround is to define a new metaclass to handle the issue:
>>> from pydantic import BaseModel
>>> from pydantic.main import ModelMetaclass
>>> from pydantic.fields import ModelPrivateAttr
>>> class DocPreservingModelMetaclass(ModelMetaclass):
... def __new__(mcs, name, bases, namespace, **kwargs):
... cls = super().__new__(mcs, name, bases, namespace, **kwargs)
... if cls.__config__.underscore_attrs_are_private:
... doc = cls.__private_attributes__.pop('__doc__', None)
... if isinstance(doc, ModelPrivateAttr):
... cls.__doc__ = doc.default
... return cls
...
>>> class MyModel(BaseModel, metaclass=DocPreservingModelMetaclass):
... """MyModel docsting."""
... class Config:
... underscore_attrs_are_private = True
...
>>> MyModel.__doc__
'MyModel docsting.'
But maybe it would be best if __doc__
was excluded via pydantic.utils.is_valid_private_name
, much like the other standard properties are excluded through this method. However, I am not sure if the latter will have other implication in the current codebase.