diff --git a/Pipfile b/Pipfile index 7ca6ae1e9..818700743 100644 --- a/Pipfile +++ b/Pipfile @@ -29,7 +29,7 @@ twilio = ">=7.0.0" uvloop = {version = "*", markers = "sys_platform != 'win32'"} [dev-packages] -hypothesis = "<=6.47.1" # Later versions add a prerelease dependency. See https://github.com/pypa/pipenv/issues/1760 +hypothesis = "*" # Versions between 6.47.1 and 6.56.4 added a prerelease dependency. See https://github.com/pypa/pipenv/issues/1760 pdoc3 = "*" pytest = "*" pytest-asyncio = "*" diff --git a/Pipfile.lock b/Pipfile.lock index d99ed9e25..80d8f40df 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "dda5f2cc5ba985d2e558bad43e5994fbf581c42bf1fd2a40ad8ca6f27cac9f74" + "sha256": "b3da1b047f70a6659401f07cd87ba09dbec53472d498b333134e4e7e4db7d9f6" }, "pipfile-spec": 6, "requires": { @@ -670,7 +670,7 @@ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.8.2" }, "pytz": { @@ -747,7 +747,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "sortedcontainers": { @@ -1049,11 +1049,11 @@ }, "hypothesis": { "hashes": [ - "sha256:4ad26c5d434171ffc02aba569dd52255573d615554c062bc30734dbe6f318c61", - "sha256:69978811f1d9c19710c7d2bf8233dc43c80efa964251b72efbe8274044e073b4" + "sha256:1901688aac1fc8d78d5431c4a1d48cc50940e247dd8b6ebc3d4167ef31204e10", + "sha256:2fd2c9640ea4b64d06fafc8d9aa8e9cbae365879d109a859afd37dda5c1ffb55" ], "index": "pypi", - "version": "==6.47.1" + "version": "==6.72.1" }, "iniconfig": { "hashes": [ @@ -1204,7 +1204,7 @@ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", "version": "==0.10.2" }, "tomli": { diff --git a/tests/utils/hypothesis.py b/tests/utils/hypothesis.py index d1dc0a154..f6cb81163 100644 --- a/tests/utils/hypothesis.py +++ b/tests/utils/hypothesis.py @@ -1,11 +1,12 @@ import asyncio import contextlib -import inspect import itertools +from inspect import Parameter, Signature import pytest from hypothesis.internal.reflection import ( define_function_signature, + get_signature, impersonate ) @@ -18,13 +19,13 @@ def autocontext(*auto_args): that requires the `request` fixture won't work. """ def decorate_test(test): - original_argspec = inspect.getfullargspec(test) - argspec = new_argspec(original_argspec, auto_args) + original_signature = get_signature(test) + signature = new_signature(original_signature, auto_args) if asyncio.iscoroutinefunction(test): @pytest.mark.asyncio @impersonate(test) - @define_function_signature(test.__name__, test.__doc__, argspec) + @define_function_signature(test.__name__, test.__doc__, signature) async def wrapped_test(*args, **kwargs): # Tell pytest to omit the body of this function from tracebacks __tracebackhide__ = True @@ -54,7 +55,7 @@ async def wrapped_test(*args, **kwargs): return wrapped_test else: @impersonate(test) - @define_function_signature(test.__name__, test.__doc__, argspec) + @define_function_signature(test.__name__, test.__doc__, signature) def wrapped_test(*args, **kwargs): # Tell pytest to omit the body of this function from tracebacks __tracebackhide__ = True @@ -77,25 +78,19 @@ def wrapped_test(*args, **kwargs): return decorate_test -def new_argspec(original_argspec, auto_args): - """Make an updated argspec for the wrapped test.""" - replaced_args = { - original_arg: auto_arg - for original_arg, auto_arg in zip( - original_argspec.args[:len(auto_args)], - auto_args - ) - } - new_args = tuple(itertools.chain( - auto_args, - original_argspec.args[len(auto_args):] +def new_signature(original_signature: Signature, auto_args): + """Make an updated signature for the wrapped test.""" + # Replace the parameter names in the original signature with the names + # of the fixtures given to @autocontext(...) so that pytest will inject the + # right fixtures. + new_parameters = tuple(itertools.chain( + [ + Parameter(name, Parameter.POSITIONAL_OR_KEYWORD) + for name in auto_args + ], + list(original_signature.parameters.values())[len(auto_args):] )) - annots = { - replaced_args.get(k) or k: v - for k, v in original_argspec.annotations.items() - } - annots["return"] = None - return original_argspec._replace( - args=new_args, - annotations=annots + return original_signature.replace( + parameters=new_parameters, + return_annotation=None )