Repository: pydantic/pydantic

Issue:
Can't parse_raw Optional[Json] generated from Pydantic
# Bug

Please complete:
* OS: any
* Python version `import sys; print(sys.version)`:3.7.3 (default, Mar 27 2019, 09:23:15)
[Clang 10.0.1 (clang-1001.0.46.3)]
* Pydantic version `import pydantic; print(pydantic.VERSION)`: 1.2

Where possible please include a self contained code snippet describing your bug:

```py
from typing import Optional
from pydantic import Json, BaseModel

class Test(BaseModel):
    name: str
    some_obj: Optional[Json]

t = Test(name="hi")
serialized = t.json()
print(serialized)
t_deserialized = Test.parse_raw(serialized)
```

The above will fail with:

```
pydantic.error_wrappers.ValidationError: 1 validation error for Test
some_obj
  JSON object must be str, bytes or bytearray (type=type_error.json)
```
Because `serialized` is JSON that takes the following form: `{"name": "hi", "some_obj": null}`. If the `some_obj` key is omitted entirely everything works fine.

I would expect `parse_raw()` to work with the output of `json()`.

The crux of the issue seems to be that validation will fail if an Optional[Json] field is present, but has a value of `None`. This will also fail `Test(name='foo', some_obj=None)`. 

This example works fine in pydantic < 1.
Can't parse_raw Optional[Json] generated from Pydantic
# Bug

Please complete:
* OS: any
* Python version `import sys; print(sys.version)`:3.7.3 (default, Mar 27 2019, 09:23:15)
[Clang 10.0.1 (clang-1001.0.46.3)]
* Pydantic version `import pydantic; print(pydantic.VERSION)`: 1.2

Where possible please include a self contained code snippet describing your bug:

```py
from typing import Optional
from pydantic import Json, BaseModel

class Test(BaseModel):
    name: str
    some_obj: Optional[Json]

t = Test(name="hi")
serialized = t.json()
print(serialized)
t_deserialized = Test.parse_raw(serialized)
```

The above will fail with:

```
pydantic.error_wrappers.ValidationError: 1 validation error for Test
some_obj
  JSON object must be str, bytes or bytearray (type=type_error.json)
```
Because `serialized` is JSON that takes the following form: `{"name": "hi", "some_obj": null}`. If the `some_obj` key is omitted entirely everything works fine.

I would expect `parse_raw()` to work with the output of `json()`.

The crux of the issue seems to be that validation will fail if an Optional[Json] field is present, but has a value of `None`. This will also fail `Test(name='foo', some_obj=None)`. 

This example works fine in pydantic < 1.


Discussion:
Thanks for reporting, shouldn't be too hard to fix. PR welcome to fix it, otherwise I'll try to fix before the next release.
Thanks for reporting, shouldn't be too hard to fix. PR welcome to fix it, otherwise I'll try to fix before the next release.

Resolving patch:
diff --git a/pydantic/validators.py b/pydantic/validators.py
--- a/pydantic/validators.py
+++ b/pydantic/validators.py
@@ -424,6 +424,9 @@ def constr_strip_whitespace(v: 'StrBytes', field: 'ModelField', config: 'BaseCon
 
 
 def validate_json(v: Any, config: 'BaseConfig') -> Any:
+    if v is None:
+        # pass None through to other validators
+        return v
     try:
         return config.json_loads(v)  # type: ignore
     except ValueError:


Test patch:
diff --git a/tests/test_types.py b/tests/test_types.py
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -6,7 +6,7 @@
 from decimal import Decimal
 from enum import Enum, IntEnum
 from pathlib import Path
-from typing import Dict, FrozenSet, Iterator, List, MutableSet, NewType, Pattern, Sequence, Set, Tuple
+from typing import Dict, FrozenSet, Iterator, List, MutableSet, NewType, Optional, Pattern, Sequence, Set, Tuple
 from uuid import UUID
 
 import pytest
@@ -1649,6 +1649,50 @@ def check(cls, v):
     assert call_count == 1
 
 
+def test_json_optional_simple():
+    class JsonOptionalModel(BaseModel):
+        json_obj: Optional[Json]
+
+    assert JsonOptionalModel(json_obj=None).dict() == {'json_obj': None}
+    assert JsonOptionalModel(json_obj='["x", "y", "z"]').dict() == {'json_obj': ['x', 'y', 'z']}
+
+
+def test_json_optional_complex():
+    class JsonOptionalModel(BaseModel):
+        json_obj: Optional[Json[List[int]]]
+
+    JsonOptionalModel(json_obj=None)
+
+    good = JsonOptionalModel(json_obj='[1, 2, 3]')
+    assert good.json_obj == [1, 2, 3]
+
+    with pytest.raises(ValidationError) as exc_info:
+        JsonOptionalModel(json_obj='["i should fail"]')
+    assert exc_info.value.errors() == [
+        {'loc': ('json_obj', 0), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}
+    ]
+
+
+def test_json_explicitly_required():
+    class JsonRequired(BaseModel):
+        json_obj: Json = ...
+
+    assert JsonRequired(json_obj=None).dict() == {'json_obj': None}
+    assert JsonRequired(json_obj='["x", "y", "z"]').dict() == {'json_obj': ['x', 'y', 'z']}
+    with pytest.raises(ValidationError) as exc_info:
+        JsonRequired()
+    assert exc_info.value.errors() == [{'loc': ('json_obj',), 'msg': 'field required', 'type': 'value_error.missing'}]
+
+
+def test_json_no_default():
+    class JsonRequired(BaseModel):
+        json_obj: Json
+
+    assert JsonRequired(json_obj=None).dict() == {'json_obj': None}
+    assert JsonRequired(json_obj='["x", "y", "z"]').dict() == {'json_obj': ['x', 'y', 'z']}
+    assert JsonRequired().dict() == {'json_obj': None}
+
+
 def test_pattern():
     class Foobar(BaseModel):
         pattern: Pattern