Repository: pydantic/pydantic

Issue:
TypeError: issubclass() arg 1 must be a class for a Pattern Field
# Bug

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.5.1
            pydantic compiled: False
                 install path: /home/yury/.cache/pypoetry/virtualenvs/chatbot-py3.6/lib/python3.6/site-packages/pydantic
               python version: 3.6.9 (default, Jul 17 2020, 12:50:27)  [GCC 8.4.0]
                     platform: Linux-5.3.0-62-generic-x86_64-with-Ubuntu-18.04-bionic
     optional deps. installed: ['typing-extensions', 'email-validator']
```
<!-- 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                                                                                                                                                                      
from pydantic.schema import model_process_schema
from typing import Pattern

class Test(BaseModel): 
    f : Pattern

model_process_schema(Test, model_name_map={})                                                                                                                                                      

```
```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-c3756917c641> in <module>
----> 1 model_process_schema(Test, model_name_map={})

~/.cache/pypoetry/virtualenvs/chatbot-py3.6/lib/python3.6/site-packages/pydantic/schema.py in model_process_schema(model, by_alias, model_name_map, ref_prefix, known_models)
    454     known_models.add(model)
    455     m_schema, m_definitions, nested_models = model_type_schema(
--> 456         model, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix, known_models=known_models
    457     )
    458     s.update(m_schema)

~/.cache/pypoetry/virtualenvs/chatbot-py3.6/lib/python3.6/site-packages/pydantic/schema.py in model_type_schema(model, by_alias, model_name_map, ref_prefix, known_models)
    490         try:
    491             f_schema, f_definitions, f_nested_models = field_schema(
--> 492                 f, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix, known_models=known_models
    493             )
    494         except SkipField as skip:

~/.cache/pypoetry/virtualenvs/chatbot-py3.6/lib/python3.6/site-packages/pydantic/schema.py in field_schema(field, by_alias, model_name_map, ref_prefix, known_models)
    189         schema_overrides=schema_overrides,
    190         ref_prefix=ref_prefix,
--> 191         known_models=known_models or set(),
    192     )
    193     # $ref will only be returned when there are no schema_overrides

~/.cache/pypoetry/virtualenvs/chatbot-py3.6/lib/python3.6/site-packages/pydantic/schema.py in field_type_schema(field, by_alias, model_name_map, schema_overrides, ref_prefix, known_models)
    416             schema_overrides=schema_overrides,
    417             ref_prefix=ref_prefix,
--> 418             known_models=known_models,
    419         )
    420         definitions.update(f_definitions)

~/.cache/pypoetry/virtualenvs/chatbot-py3.6/lib/python3.6/site-packages/pydantic/schema.py in field_singleton_schema(field, by_alias, model_name_map, schema_overrides, ref_prefix, known_models)
    642         f_schema['const'] = literal_value
    643 
--> 644     if issubclass(field_type, Enum):
    645         f_schema.update({'enum': [item.value for item in field_type]})
    646         # Don't return immediately, to allow adding specific types

TypeError: issubclass() arg 1 must be a class

```



Discussion:

Resolving patch:
diff --git a/docs/build/schema_mapping.py b/docs/build/schema_mapping.py
--- a/docs/build/schema_mapping.py
+++ b/docs/build/schema_mapping.py
@@ -145,6 +145,13 @@
         'JSON Schema Validation',
         ''
     ],
+    [
+        'Pattern',
+        'string',
+        {'format': 'regex'},
+        'JSON Schema Validation',
+        ''
+    ],
     [
         'bytes',
         'string',
diff --git a/pydantic/schema.py b/pydantic/schema.py
--- a/pydantic/schema.py
+++ b/pydantic/schema.py
@@ -14,6 +14,7 @@
     Iterable,
     List,
     Optional,
+    Pattern,
     Sequence,
     Set,
     Tuple,
@@ -618,6 +619,7 @@ def field_singleton_sub_fields_schema(
     (IPv6Interface, {'type': 'string', 'format': 'ipv6interface'}),
     (IPv4Address, {'type': 'string', 'format': 'ipv4'}),
     (IPv6Address, {'type': 'string', 'format': 'ipv6'}),
+    (Pattern, {'type': 'string', 'format': 'regex'}),
     (str, {'type': 'string'}),
     (bytes, {'type': 'string', 'format': 'binary'}),
     (bool, {'type': 'boolean'}),
@@ -643,7 +645,8 @@ def add_field_type_to_schema(field_type: Any, schema: Dict[str, Any]) -> None:
     and then modifies the given `schema` with the information from that type.
     """
     for type_, t_schema in field_class_to_schema:
-        if issubclass(field_type, type_):
+        # Fallback for `typing.Pattern` as it is not a valid class
+        if lenient_issubclass(field_type, type_) or field_type is type_ is Pattern:
             schema.update(t_schema)
             break
 


Test patch:
diff --git a/tests/test_types.py b/tests/test_types.py
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -2055,6 +2055,13 @@ class Foobar(BaseModel):
     f2 = Foobar(pattern=p)
     assert f2.pattern is p
 
+    assert Foobar.schema() == {
+        'type': 'object',
+        'title': 'Foobar',
+        'properties': {'pattern': {'type': 'string', 'format': 'regex', 'title': 'Pattern'}},
+        'required': ['pattern'],
+    }
+
 
 def test_pattern_error():
     class Foobar(BaseModel):