Repository: pydantic/pydantic

Issue:
How to use a field called "self"
# Question
Is it possible to have a field on a model called "self"?
(Background to the question is JSON-API has links called "self", "related" etc.)

* Python version 3.7.3
* Pydantic version 0.29

```py
from pydantic import BaseModel

class Model(BaseModel):
    self: str

m = Model(self="some URL")
# TypeError: __init__() got multiple values for argument 'self'
```

I tried calling the field "self_" using an alias called "self"

```py
from pydantic import BaseModel, Schema

class Model(BaseModel):
    self_: str = Schema(alias="self")

m = Model(self="some URL")
# TypeError: __init__() got multiple values for argument 'self'
```


Discussion:
Try `m = Model(self_=“some URL”)` with the rest of the code as is (from the with-alias example).
@dmontagu the problem is deserialization. 
I get a json body in a request with {"self": "someurl"} in it and I can't create a model instance without preparsing the body to replace "self" with "self_"

If pydantic had a way to "preload" like marshmallow does it might help?
Would #624 help? 
@samuelcolvin would having a load alias give you a different function to call that didn’t already have `self` as a parameter? I don’t see that discussed in the linked issue.

Given how frequently the specific field name `self` seems to be desired (I think it has meaning in certain json schema specs), might it make sense to rename `self` to `__self__` or something else equally unlikely to cause conflicts in `BaseModel.__init__` (and perhaps other methods expecting field names as kwargs)? Unless the approach of calling `Model(**data)` to initialize a model becomes discouraged, it feels unfortunate to me to have to change the model initialization code just to support a reasonably-named field (reasonable in a JSON context, rather than a python context anyway).
@samuelcolvin not sure whether splitting out load and dump aliases changes the fact.

Seems to me being able to avoid `Model(**data)` to initialize a model avoids all sorts of possible issues with name clashes. Moving this to a 'marshmallow' style `load(...)` has other advantages for pre-formatting data etc. but I don't really want to suggest any specific approach here not knowing the history and roadmap of the project well enough, rather just if there is a way to handle this.

Regardless, as @dmontagu points out, 'self' and even 'kwargs' should be possible to specify in a schema.

Resolving patch:
diff --git a/pydantic/main.py b/pydantic/main.py
--- a/pydantic/main.py
+++ b/pydantic/main.py
@@ -358,7 +358,12 @@ def parse_obj(cls: Type['Model'], obj: Any) -> 'Model':
                 except (TypeError, ValueError) as e:
                     exc = TypeError(f'{cls.__name__} expected dict not {type(obj).__name__}')
                     raise ValidationError([ErrorWrapper(exc, loc='__obj__')]) from e
-        return cls(**obj)
+
+        m = cls.__new__(cls)
+        values, fields_set, _ = validate_model(m, obj)
+        object.__setattr__(m, '__values__', values)
+        object.__setattr__(m, '__fields_set__', fields_set)
+        return m
 
     @classmethod
     def parse_raw(
@@ -472,14 +477,14 @@ def __get_validators__(cls) -> 'CallableGenerator':
     @classmethod
     def validate(cls: Type['Model'], value: Any) -> 'Model':
         if isinstance(value, dict):
-            return cls(**value)
+            return cls.parse_obj(value)
         elif isinstance(value, cls):
             return value.copy()
         elif cls.__config__.orm_mode:
             return cls.from_orm(value)
         else:
             with change_exception(DictError, TypeError, ValueError):
-                return cls(**dict(value))
+                return cls.parse_obj(value)
 
     @classmethod
     def _decompose_class(cls: Type['Model'], obj: Any) -> GetterDict:


Test patch:
diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py
--- a/tests/test_edge_cases.py
+++ b/tests/test_edge_cases.py
@@ -880,3 +880,29 @@ class Spam(BaseModel):
     assert Spam(c=Foo(a='123')).dict() == {'c': {'a': 123}}
     with pytest.raises(ValidationError):
         Spam(c=Bar(b='123'))
+
+
+def test_self():
+    class Model(BaseModel):
+        self: str
+
+    m = Model.parse_obj(dict(self='some value'))
+    assert m.dict() == {'self': 'some value'}
+    assert m.self == 'some value'
+    assert m.schema() == {
+        'title': 'Model',
+        'type': 'object',
+        'properties': {'self': {'title': 'Self', 'type': 'string'}},
+        'required': ['self'],
+    }
+
+
+def test_self_recursive():
+    class SubModel(BaseModel):
+        self: int
+
+    class Model(BaseModel):
+        sm: SubModel
+
+    m = Model.parse_obj({'sm': {'self': '123'}})
+    assert m.dict() == {'sm': {'self': 123}}