Repository: samuelcolvin/pydantic (python)

Issue:
Using PrivateAttr with multiple inheritance does not work because of the use of __slots__
### Checks

* [x] I added a descriptive title to this issue
* [x] I have searched (google, github) for similar issues and couldn't find anything
* [x] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug

<!-- Sorry to sound so draconian, but every second saved replying to issues is time spend improving pydantic :-) -->

# Bug

Using PrivateAttr with multiple inheritance does not work because of the use of `__slots__`. The current code sets all parent private attrs again on any child thus overwriting the parent slots. Functionally that is not really an option but it breaks the algorithm which determines if base classes clash with multiple inheritance

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.8.2
            pydantic compiled: False
                 install path: /home/HOME/git/pydantic/pydantic
               python version: 3.8.10 (default, Jun  2 2021, 10:49:15)  [GCC 9.4.0]
                     platform: Linux-5.4.0-77-generic-x86_64-with-glibc2.29
     optional deps. installed: ['devtools', 'dotenv', 'email-validator', 'typing-extensions']
```
<!-- or if you're using pydantic prior to v1.3, manually include: OS, python version and pydantic version -->

<!-- Please read the [docs](https://pydantic-docs.helpmanual.io/) and search through issues to
confirm your bug hasn't already been reported. -->

<!-- Where possible please include a self-contained code snippet describing your bug: -->

```py
from pydantic import BaseModel

default = {'a': {}}

class GrandParentModel(BaseModel):
    __foo__ = PrivateAttr(default)

class ParentAModel(GrandParentModel):
    pass

class ParentBModel(GrandParentModel):
    __bar__ = PrivateAttr(default)

class Model(ParentAModel, ParentBModel):
    __baz__ = PrivateAttr(default)
```
gives: TypeError: multiple bases have instance lay-out conflict

Pull request:
Fix error when using slots with multiple inheritance
<!-- Thank you for your contribution! -->
<!-- Unless your change is trivial, please create an issue to discuss the change before creating a PR -->
<!-- See https://pydantic-docs.helpmanual.io/contributing/ for help on Contributing -->

## Change Summary

Using PrivateAttr with multiple inheritance does not work because of the use of `__slots__`. The current code sets all parent private attrs again on any child thus overwriting the parent slots. Functionally that is not really an issue but it breaks the algorithm which determines if base classes clash with multiple inheritance

## Related issue number

closes #2988

## Checklist

* [x] Unit tests for the changes exist
* [x] Tests pass on CI and coverage remains at 100%
* [x] Documentation reflects the changes where applicable
* [x] `changes/<pull request or issue id>-<github username>.md` file added describing change
  (see [changes/README.md](https://github.com/samuelcolvin/pydantic/blob/master/changes/README.md) for details)
* [x] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**


Patch:
diff --git a/changes/2989-hmvp.md b/changes/2989-hmvp.md
new file mode 100644
index 000000000..7130d007b
--- /dev/null
+++ b/changes/2989-hmvp.md
@@ -0,0 +1,1 @@
+Make multiple inheritance work when using `PrivateAttr`
diff --git a/pydantic/main.py b/pydantic/main.py
index 7e1e3cbd4..a69023431 100644
--- a/pydantic/main.py
+++ b/pydantic/main.py
@@ -123,6 +123,7 @@ class ModelMetaclass(ABCMeta):
 
         pre_root_validators, post_root_validators = [], []
         private_attributes: Dict[str, ModelPrivateAttr] = {}
+        base_private_attributes: Dict[str, ModelPrivateAttr] = {}
         slots: SetStr = namespace.get('__slots__', ())
         slots = {slots} if isinstance(slots, str) else set(slots)
         class_vars: SetStr = set()
@@ -135,7 +136,7 @@ class ModelMetaclass(ABCMeta):
                 validators = inherit_validators(base.__validators__, validators)
                 pre_root_validators += base.__pre_root_validators__
                 post_root_validators += base.__post_root_validators__
-                private_attributes.update(base.__private_attributes__)
+                base_private_attributes.update(base.__private_attributes__)
                 class_vars.update(base.__class_vars__)
                 hash_func = base.__hash__
 
@@ -264,7 +265,7 @@ class ModelMetaclass(ABCMeta):
             '__schema_cache__': {},
             '__json_encoder__': staticmethod(json_encoder),
             '__custom_root_type__': _custom_root_type,
-            '__private_attributes__': private_attributes,
+            '__private_attributes__': {**base_private_attributes, **private_attributes},
             '__slots__': slots | private_attributes.keys(),
             '__hash__': hash_func,
             '__class_vars__': class_vars,
@@ -295,7 +296,7 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
         __schema_cache__: 'DictAny' = {}
         __custom_root_type__: bool = False
         __signature__: 'Signature'
-        __private_attributes__: Dict[str, Any]
+        __private_attributes__: Dict[str, ModelPrivateAttr]
         __class_vars__: SetStr
         __fields_set__: SetStr = set()
 


Test patch:
diff --git a/tests/test_private_attributes.py b/tests/test_private_attributes.py
index d87e572ab..0d3a0978e 100644
--- a/tests/test_private_attributes.py
+++ b/tests/test_private_attributes.py
@@ -200,3 +200,58 @@ def test_generic_private_attribute():
     m = Model[int](value=1, _private_attr=3)
     m._private_value = 3
     assert m.dict() == {'value': 1}
+
+
+def test_private_attribute_multiple_inheritance():
+    # We need to test this since PrivateAttr uses __slots__ and that has some restrictions with regards to
+    # multiple inheritance
+    default = {'a': {}}
+
+    class GrandParentModel(BaseModel):
+        __foo__ = PrivateAttr(default)
+
+    class ParentAModel(GrandParentModel):
+        pass
+
+    class ParentBModel(GrandParentModel):
+        __bar__ = PrivateAttr(default)
+
+    class Model(ParentAModel, ParentBModel):
+        __baz__ = PrivateAttr(default)
+
+    assert GrandParentModel.__slots__ == {'__foo__'}
+    assert ParentBModel.__slots__ == {'__bar__'}
+    assert Model.__slots__ == {'__baz__'}
+    assert repr(Model.__foo__) == "<member '__foo__' of 'GrandParentModel' objects>"
+    assert repr(Model.__bar__) == "<member '__bar__' of 'ParentBModel' objects>"
+    assert repr(Model.__baz__) == "<member '__baz__' of 'Model' objects>"
+    assert Model.__private_attributes__ == {
+        '__foo__': PrivateAttr(default),
+        '__bar__': PrivateAttr(default),
+        '__baz__': PrivateAttr(default),
+    }
+
+    m = Model()
+    assert m.__foo__ == default
+    assert m.__foo__ is not default
+    assert m.__foo__['a'] is not default['a']
+
+    assert m.__bar__ == default
+    assert m.__bar__ is not default
+    assert m.__bar__['a'] is not default['a']
+
+    assert m.__baz__ == default
+    assert m.__baz__ is not default
+    assert m.__baz__['a'] is not default['a']
+
+    m.__foo__ = None
+    assert m.__foo__ is None
+
+    m.__bar__ = None
+    assert m.__bar__ is None
+
+    m.__baz__ = None
+    assert m.__baz__ is None
+
+    assert m.dict() == {}
+    assert m.__dict__ == {}