Repository: samuelcolvin/pydantic
Pull request #3554 (2021-12-20 21:01:25)

build(deps): bump hypothesis from 6.31.4 to 6.31.6
Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.31.4 to 6.31.6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/HypothesisWorks/hypothesis/releases">hypothesis's releases</a>.</em></p>
<blockquote>
<h2>Hypothesis for Python - version 6.31.6</h2>
<p>This patch adds a temporary hook for a downstream tool, which is not
part of the public API.</p>
<p><em><a href="https://hypothesis.readthedocs.io/en/latest/changes.html#v6-31-6">The canonical version of these notes (with links) is on readthedocs.</a></em></p>
<h2>Hypothesis for Python - version 6.31.5</h2>
<p>This release updates our copyright headers to use a general authorship
statement and omit the year.</p>
<p><em><a href="https://hypothesis.readthedocs.io/en/latest/changes.html#v6-31-5">The canonical version of these notes (with links) is on readthedocs.</a></em></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/HypothesisWorks/hypothesis/commit/f7155d226c7e6830444b570a30c6ac1ccb7493eb"><code>f7155d2</code></a> Bump hypothesis-python version to 6.31.6 and update changelog</li>
<li><a href="https://github.com/HypothesisWorks/hypothesis/commit/99cc429968f50d7b20105ba5da2f4094a13c6609"><code>99cc429</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/HypothesisWorks/hypothesis/issues/3196">#3196</a> from Zac-HD/jsonschema-regex-hack</li>
<li><a href="https://github.com/HypothesisWorks/hypothesis/commit/ffd6211eb788325d62cbeeaa5f8ac768d36d9f91"><code>ffd6211</code></a> Temporary arg for jsonschema</li>
<li><a href="https://github.com/HypothesisWorks/hypothesis/commit/8fd286b65d0678bfc755e5f5c82e55fde2d372e7"><code>8fd286b</code></a> Bump hypothesis-python version to 6.31.5 and update changelog</li>
<li><a href="https://github.com/HypothesisWorks/hypothesis/commit/09e5035edbb68fafb1012c0e910da31d1bc3b370"><code>09e5035</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/HypothesisWorks/hypothesis/issues/3195">#3195</a> from Zac-HD/update-headers</li>
<li><a href="https://github.com/HypothesisWorks/hypothesis/commit/45e01620571970219d25123b87b0d57a2346b4e2"><code>45e0162</code></a> Create RELEASE.rst</li>
<li><a href="https://github.com/HypothesisWorks/hypothesis/commit/ce0480b6778c65406ac60bb710ef630f3d25a0c8"><code>ce0480b</code></a> Timeless copyright headers</li>
<li><a href="https://github.com/HypothesisWorks/hypothesis/commit/061dfb1b7070674f53d76f18e16ff190d680aaa2"><code>061dfb1</code></a> Accurate, timeless headers</li>
<li>See full diff in <a href="https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.31.4...hypothesis-python-6.31.6">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hypothesis&package-manager=pip&previous-version=6.31.4&new-version=6.31.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/docs/examples/schema_ad_hoc.py b/docs/examples/schema_ad_hoc.py
index 6e93f913d..10862e162 100644
--- a/docs/examples/schema_ad_hoc.py
+++ b/docs/examples/schema_ad_hoc.py
@@ -2,7 +2,7 @@ from typing import Literal, Union
 
 from typing_extensions import Annotated
 
-from pydantic import BaseModel, Field, schema_json
+from pydantic import BaseModel, Field, schema_json_of
 
 
 class Cat(BaseModel):
@@ -17,4 +17,4 @@ class Dog(BaseModel):
 
 Pet = Annotated[Union[Cat, Dog], Field(discriminator='pet_type')]
 
-print(schema_json(Pet, title='The Pet Schema', indent=2))
+print(schema_json_of(Pet, title='The Pet Schema', indent=2))
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 2bc1b7dc1..88f06ea3f 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,12 +1,12 @@
 ansi2html==1.6.0
 flake8==4.0.1
 flake8-quotes==3.3.1
-hypothesis==6.31.4
+hypothesis==6.31.6
 markdown-include==0.6.0
 mdx-truly-sane-lists==1.2
 mkdocs==1.2.3
 mkdocs-exclude==1.0.2
-mkdocs-material==8.1.1
+mkdocs-material==8.1.3
 sqlalchemy
 orjson
 ujson
diff --git a/docs/usage/schema.md b/docs/usage/schema.md
index 9928b2782..458014a41 100644
--- a/docs/usage/schema.md
+++ b/docs/usage/schema.md
@@ -39,7 +39,7 @@ will be replaced with the model naming using `str.format()`.
 
 ## Getting schema of a specified type
 
-_Pydantic_ includes two standalone utility functions `schema` and `schema_json` that can be used to
+_Pydantic_ includes two standalone utility functions `schema_of` and `schema_json_of` that can be used to
 apply the schema generation logic used for _pydantic_ models in a more ad-hoc way.
 These functions behave similarly to `BaseModel.schema` and `BaseModel.schema_json`,
 but work with arbitrary pydantic-compatible types.
diff --git a/pydantic/__init__.py b/pydantic/__init__.py
index 0443acef6..982ea4755 100644
--- a/pydantic/__init__.py
+++ b/pydantic/__init__.py
@@ -67,8 +67,8 @@ __all__ = [
     'parse_file_as',
     'parse_obj_as',
     'parse_raw_as',
-    'schema',
-    'schema_json',
+    'schema_of',
+    'schema_json_of',
     # types
     'NoneStr',
     'NoneBytes',
diff --git a/pydantic/fields.py b/pydantic/fields.py
index ff7b962f7..44a3aa10b 100644
--- a/pydantic/fields.py
+++ b/pydantic/fields.py
@@ -50,6 +50,7 @@ from .utils import (
     ValueItems,
     get_discriminator_alias_and_values,
     get_unique_discriminator_alias,
+    lenient_isinstance,
     lenient_issubclass,
     sequence_like,
     smart_deepcopy,
@@ -1048,7 +1049,7 @@ class ModelField(Representation):
                             return v, None
                     except TypeError:
                         # compound type
-                        if isinstance(v, get_origin(field.outer_type_)):
+                        if lenient_isinstance(v, get_origin(field.outer_type_)):
                             value, error = field.validate(v, values, loc=loc, cls=cls)
                             if not error:
                                 return value, None
diff --git a/pydantic/tools.py b/pydantic/tools.py
index f1d651cd4..9cdb4538e 100644
--- a/pydantic/tools.py
+++ b/pydantic/tools.py
@@ -7,7 +7,7 @@ from .parse import Protocol, load_file, load_str_bytes
 from .types import StrBytes
 from .typing import display_as_type
 
-__all__ = ('parse_file_as', 'parse_obj_as', 'parse_raw_as', 'schema', 'schema_json')
+__all__ = ('parse_file_as', 'parse_obj_as', 'parse_raw_as', 'schema_of', 'schema_json_of')
 
 NameFactory = Union[str, Callable[[Type[Any]], str]]
 
@@ -82,11 +82,11 @@ def parse_raw_as(
     return parse_obj_as(type_, obj, type_name=type_name)
 
 
-def schema(type_: Any, *, title: Optional[NameFactory] = None, **schema_kwargs: Any) -> 'DictStrAny':
+def schema_of(type_: Any, *, title: Optional[NameFactory] = None, **schema_kwargs: Any) -> 'DictStrAny':
     """Generate a JSON schema (as dict) for the passed model or dynamically generated one"""
     return _get_parsing_type(type_, type_name=title).schema(**schema_kwargs)
 
 
-def schema_json(type_: Any, *, title: Optional[NameFactory] = None, **schema_json_kwargs: Any) -> str:
+def schema_json_of(type_: Any, *, title: Optional[NameFactory] = None, **schema_json_kwargs: Any) -> str:
     """Generate a JSON schema (as JSON) for the passed model or dynamically generated one"""
     return _get_parsing_type(type_, type_name=title).schema_json(**schema_json_kwargs)
diff --git a/pydantic/utils.py b/pydantic/utils.py
index ec94f76c7..d4ca69395 100644
--- a/pydantic/utils.py
+++ b/pydantic/utils.py
@@ -53,6 +53,7 @@ __all__ = (
     'import_string',
     'sequence_like',
     'validate_field_name',
+    'lenient_isinstance',
     'lenient_issubclass',
     'in_ipython',
     'deep_update',
@@ -163,6 +164,13 @@ def validate_field_name(bases: List[Type['BaseModel']], field_name: str) -> None
             )
 
 
+def lenient_isinstance(o: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...]]) -> bool:
+    try:
+        return isinstance(o, class_or_tuple)
+    except TypeError:
+        return False
+
+
 def lenient_issubclass(cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...]]) -> bool:
     try:
         return isinstance(cls, type) and issubclass(cls, class_or_tuple)


Test patch:
diff --git a/tests/requirements-linting.txt b/tests/requirements-linting.txt
index 81614a46e..40b92adc1 100644
--- a/tests/requirements-linting.txt
+++ b/tests/requirements-linting.txt
@@ -1,7 +1,7 @@
 black==21.12b0
 flake8==4.0.1
 flake8-quotes==3.3.1
-hypothesis==6.31.4
+hypothesis==6.31.6
 isort==5.10.1
 mypy==0.910
 pre-commit==2.16.0
diff --git a/tests/requirements-testing.txt b/tests/requirements-testing.txt
index faa291edf..2e4964458 100644
--- a/tests/requirements-testing.txt
+++ b/tests/requirements-testing.txt
@@ -1,5 +1,5 @@
 coverage==6.2
-hypothesis==6.31.4
+hypothesis==6.31.6
 # pin importlib-metadata as upper versions need typing-extensions to work if on python < 3.8
 importlib-metadata==3.1.0;python_version<"3.8"
 mypy==0.910
diff --git a/tests/test_tools.py b/tests/test_tools.py
index 97784d552..689b32d4c 100644
--- a/tests/test_tools.py
+++ b/tests/test_tools.py
@@ -5,7 +5,7 @@ import pytest
 
 from pydantic import BaseModel, ValidationError
 from pydantic.dataclasses import dataclass
-from pydantic.tools import parse_file_as, parse_obj_as, parse_raw_as, schema, schema_json
+from pydantic.tools import parse_file_as, parse_obj_as, parse_raw_as, schema_json_of, schema_of
 
 
 @pytest.mark.parametrize('obj,type_,parsed', [('1', int, 1), (['1'], List[int], [1])])
@@ -101,11 +101,11 @@ def test_raw_as():
 
 
 def test_schema():
-    assert schema(Union[int, str], title='IntOrStr') == {
+    assert schema_of(Union[int, str], title='IntOrStr') == {
         'title': 'IntOrStr',
         'anyOf': [{'type': 'integer'}, {'type': 'string'}],
     }
-    assert schema_json(Union[int, str], title='IntOrStr', indent=2) == (
+    assert schema_json_of(Union[int, str], title='IntOrStr', indent=2) == (
         '{\n'
         '  "title": "IntOrStr",\n'
         '  "anyOf": [\n'
diff --git a/tests/test_types.py b/tests/test_types.py
index 2a3161316..bbf4c23b1 100644
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -27,7 +27,7 @@ from typing import (
 from uuid import UUID
 
 import pytest
-from typing_extensions import Literal
+from typing_extensions import Literal, TypedDict
 
 from pydantic import (
     UUID1,
@@ -3120,6 +3120,22 @@ def test_smart_union_compouned_types_edge_case():
     assert Model(x=[1, '2']).x == ['1', '2']
 
 
+def test_smart_union_typeddict():
+    class Dict1(TypedDict):
+        foo: str
+
+    class Dict2(TypedDict):
+        bar: str
+
+    class M(BaseModel):
+        d: Union[Dict2, Dict1]
+
+        class Config:
+            smart_union = True
+
+    assert M(d=dict(foo='baz')).d == {'foo': 'baz'}
+
+
 @pytest.mark.parametrize(
     'value,result',
     (