Repository: pydantic/pydantic

Issue:
Improve auto-generated JSON Schema title when none provided
# Feature Request
## schema.py:280
Current:
```python
s = dict(title=schema.title or field.alias.title())
```
Proposed:
```python
# provide better title for PEP8 snake case names
s = dict(title=schema.title or field.alias.title().replace('_', ' '))
```


Discussion:
Would you accept this change as a PR?
PR sounds good.

I guess no harm in including this in v1 since it's so small.
Given this breaks a lot of fastapi tests (presumably mostly just requiring modifications to generated schemas), @tiangolo do you have any issues with this change?
Okay, let's wait until v1.1.
except I guess if it's a breaking change, it would make more sense to include it in v1.

@tiangolo what do you think?
@tiangolo would you like me to also update the title field in the schema unit tests to ensure that's all it is?
I'm pro this change, it seems like a no brainer, especially if it's a breaking change, to include it in v1.

@skewty please fix the PR and I'll merge.

Resolving patch:
diff --git a/pydantic/schema.py b/pydantic/schema.py
--- a/pydantic/schema.py
+++ b/pydantic/schema.py
@@ -277,7 +277,7 @@ def field_schema(
     ref_prefix = ref_prefix or default_prefix
     schema_overrides = False
     schema = cast('Schema', field.schema)
-    s = dict(title=schema.title or field.alias.title())
+    s = dict(title=schema.title or field.alias.title().replace('_', ' '))
     if schema.title:
         schema_overrides = True
 


Test patch:
diff --git a/tests/test_dataclasses.py b/tests/test_dataclasses.py
--- a/tests/test_dataclasses.py
+++ b/tests/test_dataclasses.py
@@ -381,7 +381,7 @@ class User:
         'properties': {
             'id': {'title': 'Id', 'type': 'integer'},
             'name': {'title': 'Name', 'default': 'John Doe', 'type': 'string'},
-            'signup_ts': {'title': 'Signup_Ts', 'type': 'string', 'format': 'date-time'},
+            'signup_ts': {'title': 'Signup Ts', 'type': 'string', 'format': 'date-time'},
         },
         'required': ['id'],
     }
diff --git a/tests/test_schema.py b/tests/test_schema.py
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -705,7 +705,7 @@ class Model(BaseModel):
     assert model_schema == {
         'title': 'Model',
         'type': 'object',
-        'properties': {'ip_address': {'title': 'Ip_Address', 'type': 'string', 'format': 'ipv4'}},
+        'properties': {'ip_address': {'title': 'Ip Address', 'type': 'string', 'format': 'ipv4'}},
         'required': ['ip_address'],
     }
 
@@ -718,7 +718,7 @@ class Model(BaseModel):
     assert model_schema == {
         'title': 'Model',
         'type': 'object',
-        'properties': {'ip_address': {'title': 'Ip_Address', 'type': 'string', 'format': 'ipv6'}},
+        'properties': {'ip_address': {'title': 'Ip Address', 'type': 'string', 'format': 'ipv6'}},
         'required': ['ip_address'],
     }
 
@@ -731,7 +731,7 @@ class Model(BaseModel):
     assert model_schema == {
         'title': 'Model',
         'type': 'object',
-        'properties': {'ip_address': {'title': 'Ip_Address', 'type': 'string', 'format': 'ipvanyaddress'}},
+        'properties': {'ip_address': {'title': 'Ip Address', 'type': 'string', 'format': 'ipvanyaddress'}},
         'required': ['ip_address'],
     }
 
@@ -744,7 +744,7 @@ class Model(BaseModel):
     assert model_schema == {
         'title': 'Model',
         'type': 'object',
-        'properties': {'ip_interface': {'title': 'Ip_Interface', 'type': 'string', 'format': 'ipv4interface'}},
+        'properties': {'ip_interface': {'title': 'Ip Interface', 'type': 'string', 'format': 'ipv4interface'}},
         'required': ['ip_interface'],
     }
 
@@ -757,7 +757,7 @@ class Model(BaseModel):
     assert model_schema == {
         'title': 'Model',
         'type': 'object',
-        'properties': {'ip_interface': {'title': 'Ip_Interface', 'type': 'string', 'format': 'ipv6interface'}},
+        'properties': {'ip_interface': {'title': 'Ip Interface', 'type': 'string', 'format': 'ipv6interface'}},
         'required': ['ip_interface'],
     }
 
@@ -770,7 +770,7 @@ class Model(BaseModel):
     assert model_schema == {
         'title': 'Model',
         'type': 'object',
-        'properties': {'ip_interface': {'title': 'Ip_Interface', 'type': 'string', 'format': 'ipvanyinterface'}},
+        'properties': {'ip_interface': {'title': 'Ip Interface', 'type': 'string', 'format': 'ipvanyinterface'}},
         'required': ['ip_interface'],
     }
 
@@ -783,7 +783,7 @@ class Model(BaseModel):
     assert model_schema == {
         'title': 'Model',
         'type': 'object',
-        'properties': {'ip_network': {'title': 'Ip_Network', 'type': 'string', 'format': 'ipv4network'}},
+        'properties': {'ip_network': {'title': 'Ip Network', 'type': 'string', 'format': 'ipv4network'}},
         'required': ['ip_network'],
     }
 
@@ -796,7 +796,7 @@ class Model(BaseModel):
     assert model_schema == {
         'title': 'Model',
         'type': 'object',
-        'properties': {'ip_network': {'title': 'Ip_Network', 'type': 'string', 'format': 'ipv6network'}},
+        'properties': {'ip_network': {'title': 'Ip Network', 'type': 'string', 'format': 'ipv6network'}},
         'required': ['ip_network'],
     }
 
@@ -809,7 +809,7 @@ class Model(BaseModel):
     assert model_schema == {
         'title': 'Model',
         'type': 'object',
-        'properties': {'ip_network': {'title': 'Ip_Network', 'type': 'string', 'format': 'ipvanynetwork'}},
+        'properties': {'ip_network': {'title': 'Ip Network', 'type': 'string', 'format': 'ipvanynetwork'}},
         'required': ['ip_network'],
     }
 
@@ -1368,7 +1368,7 @@ class Model(BaseModel):
         'type': 'object',
         'properties': {
             'dep': {'$ref': '#/definitions/Dep'},
-            'dep_l': {'title': 'Dep_L', 'type': 'array', 'items': {'$ref': '#/definitions/Dep'}},
+            'dep_l': {'title': 'Dep L', 'type': 'array', 'items': {'$ref': '#/definitions/Dep'}},
         },
         'required': ['dep', 'dep_l'],
         'definitions': {