Repository: HypothesisWorks/hypothesis

Issue:
Hypothesis breaks pytest on Python 3.8
Testing against Python version: `Python 3.8.0a3+ (heads/master:be6dbfb, Apr 29 2019, 14:45:16) `, if you install `pytest` and `hypothesis` together in a virtualenv and run `pytest` at all (even in an empty directory), it throws an error:

```bash
$ python -m virtualenv venv --python=python3.8
Running virtualenv with interpreter ~/.pyenv/shims/python3.8
Using base prefix '~/.pyenv/versions/3.8-dev'
New python executable in /tmp/hypotest/venv/bin/python3.8
Also creating executable in /tmp/hypotest/venv/bin/python
Installing setuptools, pip, wheel...
done.
$ python3.8 --version
Python 3.8.0a3+
$ source venv/bin/activate
(venv) $ python --version
Python 3.8.0a3+
(venv) $ pip install pytest
...
(venv) $ pytest
======================= test session starts ======================
platform linux -- Python 3.8.0a3+, pytest-4.4.1, py-1.8.0, pluggy-0.9.0
rootdir: /tmp/hypotest
collected 0 items
================== no tests ran in 0.00 seconds ==================
(venv) $ pip install hypothesis
...
Successfully installed hypothesis-4.18.0
(venv) $ pip install hypothesis
...
TypeError: an integer is required (got type bytes)
```

The full traceback is here, in a `details` block:

<details>

```
Traceback (most recent call last):
  File "/tmp/hypotest/venv/bin/pytest", line 10, in <module>
    sys.exit(main())
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/_pytest/config/__init__.py", line 60, in main
    config = _prepareconfig(args, plugins)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/_pytest/config/__init__.py", line 200, in _prepareconfig
    return pluginmanager.hook.pytest_cmdline_parse(
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/pluggy/hooks.py", line 289, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/pluggy/manager.py", line 68, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/pluggy/manager.py", line 59, in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/pluggy/callers.py", line 203, in _multicall
    gen.send(outcome)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/_pytest/helpconfig.py", line 93, in pytest_cmdline_parse
    config = outcome.get_result()
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/pluggy/callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/pluggy/callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/_pytest/config/__init__.py", line 679, in pytest_cmdline_parse
    self.parse(args)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/_pytest/config/__init__.py", line 896, in parse
    self._preparse(args, addopts=addopts)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/_pytest/config/__init__.py", line 841, in _preparse
    self.pluginmanager.load_setuptools_entrypoints("pytest11")
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/pluggy/manager.py", line 274, in load_setuptools_entrypoints
    plugin = ep.load()
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2434, in load
    return self.resolve()
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2440, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/hypothesis/__init__.py", line 29, in <module>
    from hypothesis.core import PrintSettings, example, find, given, reproduce_failure, seed
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 618, in _load_backward_compatible
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/_pytest/assertion/rewrite.py", line 299, in load_module
    six.exec_(co, mod.__dict__)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/hypothesis/core.py", line 38, in <module>
    import hypothesis.strategies as st
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 618, in _load_backward_compatible
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/_pytest/assertion/rewrite.py", line 299, in load_module
    six.exec_(co, mod.__dict__)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/hypothesis/strategies.py", line 20, in <module>
    from hypothesis._strategies import (
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 618, in _load_backward_compatible
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/_pytest/assertion/rewrite.py", line 299, in load_module
    six.exec_(co, mod.__dict__)
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/hypothesis/_strategies.py", line 267, in <module>
    def nothing():
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/hypothesis/_strategies.py", line 184, in cacheable
    def cached_strategy(*args, **kwargs):
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/hypothesis/internal/reflection.py", line 617, in accept
    return impersonate(target)(
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/hypothesis/internal/reflection.py", line 603, in accept
    f.__code__ = update_code_location(
  File "/tmp/hypotest/venv/lib/python3.8/site-packages/hypothesis/internal/compat.py", line 409, in update_code_location
    return type(code)(*unpacked)
TypeError: an integer is required (got type bytes)
```

</details>

I'm not sure if this is a bug in hypothesis or a bug in CPython. It does suggest that adding a Python 3.8 nightly build to your CI matrix may be worthwhile, though.


Discussion:
Ah, it seems that this is due to [this](https://github.com/HypothesisWorks/hypothesis/blob/master/hypothesis-python/src/hypothesis/internal/compat.py#L377). I'm fairly sure the order of arguments in a code object's constructor is not part of the public interface, and `co_posonlyargcount` was added as part of [PEP 570](https://www.python.org/dev/peps/pep-0570/) (see: https://github.com/python/cpython/pull/12701).

Resolving patch:
diff --git a/hypothesis-python/src/hypothesis/internal/compat.py b/hypothesis-python/src/hypothesis/internal/compat.py
--- a/hypothesis-python/src/hypothesis/internal/compat.py
+++ b/hypothesis-python/src/hypothesis/internal/compat.py
@@ -392,6 +392,10 @@ def get_type_hints(thing):
         "co_cellvars",
     ]
 
+    if sys.version_info >= (3, 8, 0):
+        # PEP 570 added "positional only arguments"
+        CODE_FIELD_ORDER.insert(1, "co_posonlyargcount")
+
 
 def update_code_location(code, newfile, newlineno):
     """Take a code object and lie shamelessly about where it comes from.


Test patch: