Skip to content

Commit 3823610

Browse files
authored
Merge pull request #4131 from Zac-HD/drop-py38
Drop Python 3.8 at end of life
2 parents a81d155 + df28a74 commit 3823610

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+351
-542
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ jobs:
2929
- check-format
3030
- check-coverage
3131
- check-conjecture-coverage
32-
- check-py38-cover
33-
- check-py38-nocover
34-
- check-py38-niche
35-
- check-pypy38-cover
3632
- check-py39-cover
3733
- check-pypy39-cover
3834
- check-py310-cover
@@ -91,7 +87,7 @@ jobs:
9187
# - check-crosshair-custom-pytest/test_*
9288
# - check-crosshair-nocover
9389
# - check-crosshair-niche
94-
- check-py38-oldestnumpy
90+
- check-py39-oldestnumpy
9591
- check-numpy-nightly
9692
fail-fast: false
9793
steps:
@@ -197,7 +193,6 @@ jobs:
197193
strategy:
198194
matrix:
199195
task:
200-
- check-py38-cover
201196
- check-py310-cover
202197
- check-py310-nocover
203198
- check-py310-niche

CONTRIBUTING.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,11 @@ high level, the task takes the form:
208208
Namely, first provide the tox environment (see ``tox.ini``), then the python
209209
version to test with, then any ``tox`` or ``pytest`` args as needed. For
210210
example, to run all of the tests in the file
211-
``tests/nocover/test_conjecture_engine.py`` with python 3.8:
211+
``tests/nocover/test_conjecture_engine.py`` with python 3.12:
212212

213213
.. code-block::
214214
215-
./build.sh tox py38-custom 3.8.13 -- tests/nocover/test_conjecture_engine.py
215+
./build.sh tox py312-custom 3.12.7 -- tests/nocover/test_conjecture_engine.py
216216
217217
See the ``tox`` docs and ``pytest`` docs for more information:
218218
* https://docs.pytest.org/en/latest/how-to/usage.html

hypothesis-python/RELEASE.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
RELEASE_TYPE: minor
2+
3+
This release drops support for Python 3.8, `which reached end of life on
4+
2024-10-07 <https://devguide.python.org/versions/>`__.

hypothesis-python/docs/supported.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ exactly where an error came from, or turn only our warnings into errors.
4545
Python versions
4646
---------------
4747

48-
Hypothesis is supported and tested on CPython 3.8+, i.e.
48+
Hypothesis is supported and tested on CPython 3.9+, i.e.
4949
`all versions of CPython with upstream support <https://devguide.python.org/versions/>`_,
5050
along with PyPy for the same versions.
5151
32-bit builds of CPython also work, though we only test them on Windows.

hypothesis-python/scripts/basic-test.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ if [ "$(python -c $'import platform, sys; print(sys.version_info.releaselevel ==
4747
$PYTEST tests/codemods/
4848
pip uninstall -y libcst click
4949

50-
if [ "$(python -c 'import sys; print(sys.version_info[:2] == (3, 8))')" = "True" ] ; then
51-
# Per NEP-29, this is the last version to support Python 3.8
52-
pip install numpy==1.24.3
50+
if [ "$(python -c 'import sys; print(sys.version_info[:2] == (3, 9))')" = "True" ] ; then
51+
# Per NEP-29, this is the last version to support Python 3.9
52+
pip install numpy==2.0.2
5353
else
5454
pip install "$(grep 'numpy==' ../requirements/coverage.txt)"
5555
fi

hypothesis-python/scripts/other-tests.sh

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,9 @@ if [[ "$HYPOTHESIS_PROFILE" != "crosshair" ]]; then
3535
pip uninstall -y typing_extensions
3636
fi
3737

38-
if [ "$(python -c 'import sys; print(sys.version_info[:2] >= (3, 9))')" = "True" ] ; then
39-
pip install "$(grep 'annotated-types==' ../requirements/coverage.txt)"
40-
$PYTEST tests/test_annotated_types.py
41-
pip uninstall -y annotated-types
42-
fi
38+
pip install "$(grep 'annotated-types==' ../requirements/coverage.txt)"
39+
$PYTEST tests/test_annotated_types.py
40+
pip uninstall -y annotated-types
4341

4442
pip install ".[lark]"
4543
pip install "$(grep -oE 'lark>=([0-9.]+)' ../hypothesis-python/setup.py | tr '>' =)"
@@ -52,17 +50,15 @@ if [ "$(python -c $'import platform, sys; print(sys.version_info.releaselevel ==
5250
pip install ".[codemods,cli]"
5351
$PYTEST tests/codemods/
5452

55-
if [ "$(python -c 'import sys; print(sys.version_info[:2] == (3, 8))')" = "True" ] ; then
56-
# Per NEP-29, this is the last version to support Python 3.8
57-
pip install numpy==1.24.3
53+
if [ "$(python -c 'import sys; print(sys.version_info[:2] == (3, 9))')" = "True" ] ; then
54+
# Per NEP-29, this is the last version to support Python 3.9
55+
pip install numpy==2.0.2
5856
else
5957
pip install "$(grep 'numpy==' ../requirements/coverage.txt)"
6058
fi
6159

6260
pip install "$(grep -E 'black(==| @)' ../requirements/coverage.txt)"
63-
if [ "$(python -c 'import sys; print(sys.version_info[:2] >= (3, 9))')" = "True" ] ; then
64-
$PYTEST tests/patching/
65-
fi
61+
$PYTEST tests/patching/
6662
pip uninstall -y libcst
6763

6864
$PYTEST tests/ghostwriter/

hypothesis-python/setup.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414

1515
import setuptools
1616

17-
if sys.version_info[:2] < (3, 8): # noqa # "unreachable" sanity check
17+
if sys.version_info[:2] < (3, 9): # "unreachable" sanity check
1818
raise Exception(
1919
"You are trying to install Hypothesis using Python "
20-
f"{sys.version.split()[0]}, but it requires Python 3.8 or later."
20+
f"{sys.version.split()[0]}, but it requires Python 3.9 or later."
2121
"Update `pip` and `setuptools`, try again, and you will automatically "
2222
"get the latest compatible version of Hypothesis instead. "
2323
"See also https://python3statement.org/practicalities/"
@@ -55,23 +55,21 @@ def local_file(name):
5555
"pytz": ["pytz>=2014.1"],
5656
"dateutil": ["python-dateutil>=1.4"],
5757
"lark": ["lark>=0.10.1"], # probably still works with old `lark-parser` too
58-
"numpy": ["numpy>=1.17.3"], # oldest with wheels for non-EOL Python (for now)
58+
"numpy": ["numpy>=1.19.3"], # oldest with wheels for non-EOL Python (for now)
5959
"pandas": ["pandas>=1.1"],
6060
"pytest": ["pytest>=4.6"],
6161
"dpcontracts": ["dpcontracts>=0.4"],
6262
"redis": ["redis>=3.0.0"],
6363
"crosshair": ["hypothesis-crosshair>=0.0.14", "crosshair-tool>=0.0.73"],
64-
# zoneinfo is an odd one: every dependency is conditional, because they're
65-
# only necessary on old versions of Python or Windows systems or emscripten.
64+
# zoneinfo is an odd one: every dependency is platform-conditional.
6665
"zoneinfo": [
6766
"tzdata>=2024.2 ; sys_platform == 'win32' or sys_platform == 'emscripten'",
68-
"backports.zoneinfo>=0.2.1 ; python_version<'3.9'",
6967
],
7068
# We only support Django versions with upstream support - see
7169
# https://www.djangoproject.com/download/#supported-versions
7270
# We also leave the choice of timezone library to the user, since it
7371
# might be zoneinfo or pytz depending on version and configuration.
74-
"django": ["django>=3.2"],
72+
"django": ["django>=4.2"],
7573
}
7674

7775
extras["all"] = sorted(set(sum(extras.values(), [])))
@@ -101,7 +99,7 @@ def local_file(name):
10199
"exceptiongroup>=1.0.0 ; python_version<'3.11'",
102100
"sortedcontainers>=2.1.0,<3.0.0",
103101
],
104-
python_requires=">=3.8",
102+
python_requires=">=3.9",
105103
classifiers=[
106104
"Development Status :: 5 - Production/Stable",
107105
"Framework :: Hypothesis",
@@ -114,7 +112,6 @@ def local_file(name):
114112
"Programming Language :: Python",
115113
"Programming Language :: Python :: 3",
116114
"Programming Language :: Python :: 3 :: Only",
117-
"Programming Language :: Python :: 3.8",
118115
"Programming Language :: Python :: 3.9",
119116
"Programming Language :: Python :: 3.10",
120117
"Programming Language :: Python :: 3.11",

hypothesis-python/src/hypothesis/core.py

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,15 @@
2424
import warnings
2525
import zlib
2626
from collections import defaultdict
27+
from collections.abc import Coroutine, Hashable
2728
from functools import partial
2829
from random import Random
2930
from typing import (
3031
TYPE_CHECKING,
3132
Any,
3233
BinaryIO,
3334
Callable,
34-
Coroutine,
35-
Hashable,
36-
List,
3735
Optional,
38-
Tuple,
39-
Type,
4036
TypeVar,
4137
Union,
4238
overload,
@@ -179,7 +175,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
179175
if not (args or kwargs):
180176
raise InvalidArgument("An example must provide at least one argument")
181177

182-
self.hypothesis_explicit_examples: List[Example] = []
178+
self.hypothesis_explicit_examples: list[Example] = []
183179
self._this_example = Example(tuple(args), kwargs)
184180

185181
def __call__(self, test: TestFunc) -> TestFunc:
@@ -194,7 +190,7 @@ def xfail(
194190
*,
195191
reason: str = "",
196192
raises: Union[
197-
Type[BaseException], Tuple[Type[BaseException], ...]
193+
type[BaseException], tuple[type[BaseException], ...]
198194
] = BaseException,
199195
) -> "example":
200196
"""Mark this example as an expected failure, similarly to
@@ -209,7 +205,7 @@ def xfail(
209205
@example(...).xfail()
210206
@example(...).xfail(reason="Prices must be non-negative")
211207
@example(...).xfail(raises=(KeyError, ValueError))
212-
@example(...).xfail(sys.version_info[:2] >= (3, 9), reason="needs py39+")
208+
@example(...).xfail(sys.version_info[:2] >= (3, 12), reason="needs py 3.12")
213209
@example(...).xfail(condition=sys.platform != "linux", raises=OSError)
214210
def test(x):
215211
pass
@@ -229,21 +225,6 @@ def test_fraction(x, y):
229225
# strategy. If we happen to generate y=0, the test will fail
230226
# because only the explicit example is treated as xfailing.
231227
x / y
232-
233-
Note that this "method chaining" syntax requires Python 3.9 or later, for
234-
:pep:`614` relaxing grammar restrictions on decorators. If you need to
235-
support older versions of Python, you can use an identity function:
236-
237-
.. code-block:: python
238-
239-
def identity(x):
240-
return x
241-
242-
243-
@identity(example(...).xfail())
244-
def test(x):
245-
pass
246-
247228
"""
248229
check_type(bool, condition, "condition")
249230
check_type(str, reason, "reason")
@@ -284,21 +265,6 @@ def via(self, whence: str, /) -> "example":
284265
@example(...).via("hy-target-$label")
285266
def test(x):
286267
pass
287-
288-
Note that this "method chaining" syntax requires Python 3.9 or later, for
289-
:pep:`614` relaxing grammar restrictions on decorators. If you need to
290-
support older versions of Python, you can use an identity function:
291-
292-
.. code-block:: python
293-
294-
def identity(x):
295-
return x
296-
297-
298-
@identity(example(...).via("label"))
299-
def test(x):
300-
pass
301-
302268
"""
303269
if not isinstance(whence, str):
304270
raise InvalidArgument(".via() must be passed a string")
@@ -1359,7 +1325,7 @@ def _raise_to_user(
13591325
for note in fragments:
13601326
add_note(err, note)
13611327
if note.startswith(failing_prefix):
1362-
ls.append(note[len(failing_prefix) :])
1328+
ls.append(note.removeprefix(failing_prefix))
13631329
if current_pytest_item.value:
13641330
current_pytest_item.value._hypothesis_failing_examples = ls
13651331

@@ -1855,7 +1821,7 @@ def find(
18551821
)
18561822
specifier.validate()
18571823

1858-
last: List[Ex] = []
1824+
last: list[Ex] = []
18591825

18601826
@settings
18611827
@given(specifier)

hypothesis-python/src/hypothesis/extra/_patching.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,6 @@ def __call_node_to_example_dec(self, node, via):
112112
else node.args
113113
),
114114
)
115-
# Note: calling a method on a decorator requires PEP-614, i.e. Python 3.9+,
116-
# but plumbing two cases through doesn't seem worth the trouble :-/
117115
via = cst.Call(
118116
func=cst.Attribute(node, cst.Name("via")),
119117
args=[cst.Arg(cst.SimpleString(repr(via)))],

0 commit comments

Comments
 (0)