Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b64f231

Browse files
Drop support for Python 3.8 (#1203)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 8243b02 commit b64f231

File tree

9 files changed

+41
-48
lines changed

9 files changed

+41
-48
lines changed

.codecov.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
codecov:
44
notify:
5-
after_n_builds: 24 # The number of test matrix+lint jobs uploading coverage
5+
after_n_builds: 22 # The number of test matrix+lint jobs uploading coverage
66
wait_for_ci: false
77

88
require_ci_to_pass: false

.github/workflows/ci-cd.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ jobs:
190190
- >-
191191
3.10
192192
- 3.9
193-
- 3.8
194193
no-extensions: ['', 'Y']
195194
os:
196195
- ubuntu-latest
@@ -211,10 +210,6 @@ jobs:
211210
no-extensions: Y
212211
experimental: false
213212
os: ubuntu-latest
214-
- pyver: pypy-3.8
215-
no-extensions: Y
216-
experimental: false
217-
os: ubuntu-latest
218213
fail-fast: false
219214
runs-on: ${{ matrix.os }}
220215
timeout-minutes: 5

.github/workflows/reusable-linters.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ jobs:
6363
with:
6464
token: ${{ secrets.codecov-token }}
6565
files: >-
66+
.tox/.tmp/.mypy/python-3.13/cobertura.xml,
6667
.tox/.tmp/.mypy/python-3.12/cobertura.xml,
6768
.tox/.tmp/.mypy/python-3.10/cobertura.xml,
68-
.tox/.tmp/.mypy/python-3.8/cobertura.xml
69+
.tox/.tmp/.mypy/python-3.9/cobertura.xml
6970
flags: >-
7071
CI-GHA,
7172
MyPy

.pre-commit-config.yaml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ repos:
7474
rev: 'v3.17.0'
7575
hooks:
7676
- id: pyupgrade
77-
args: ['--py38-plus']
77+
args: ['--py39-plus']
7878
- repo: https://github.com/PyCQA/flake8
7979
rev: '7.1.1'
8080
hooks:
@@ -166,8 +166,8 @@ repos:
166166
- --html-report=.tox/.tmp/.mypy/python-3.10
167167
pass_filenames: false
168168
- id: mypy
169-
alias: mypy-py38
170-
name: MyPy, for Python 3.8
169+
alias: mypy-py39
170+
name: MyPy, for Python 3.9
171171
additional_dependencies:
172172
- hypothesis
173173
- lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report`
@@ -180,10 +180,10 @@ repos:
180180
- types-colorama
181181
- pytest_codspeed
182182
args:
183-
- --python-version=3.8
184-
- --txt-report=.tox/.tmp/.mypy/python-3.8
185-
- --cobertura-xml-report=.tox/.tmp/.mypy/python-3.8
186-
- --html-report=.tox/.tmp/.mypy/python-3.8
183+
- --python-version=3.9
184+
- --txt-report=.tox/.tmp/.mypy/python-3.9
185+
- --cobertura-xml-report=.tox/.tmp/.mypy/python-3.9
186+
- --html-report=.tox/.tmp/.mypy/python-3.9
187187
pass_filenames: false
188188

189189
- repo: https://github.com/rhysd/actionlint.git

CHANGES/1203.breaking.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Removed support for Python 3.8 as it has reached end of life -- by :user:`bdraco`.

setup.cfg

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ classifiers =
3838
Programming Language :: Cython
3939
Programming Language :: Python
4040
Programming Language :: Python :: 3
41-
Programming Language :: Python :: 3.8
4241
Programming Language :: Python :: 3.9
4342
Programming Language :: Python :: 3.10
4443
Programming Language :: Python :: 3.11
@@ -53,7 +52,7 @@ keywords =
5352
yarl
5453

5554
[options]
56-
python_requires = >=3.8
55+
python_requires = >=3.9
5756
# Ref:
5857
# https://setuptools.pypa.io/en/latest/userguide/declarative_config.html#using-a-src-layout
5958
# (`src/` layout)

tests/test_quoting.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import os
2-
from typing import Type
32

43
import pytest
54
from hypothesis import assume, example, given, note
@@ -503,8 +502,8 @@ def test_fuzz__PyUnquoter(ignore, unsafe, qs):
503502
@pytest.mark.parametrize("quoter", quoters, ids=quoter_ids)
504503
@pytest.mark.parametrize("unquoter", unquoters, ids=unquoter_ids)
505504
def test_quote_unquote_parameter(
506-
quoter: Type[_PyQuoter],
507-
unquoter: Type[_PyUnquoter],
505+
quoter: type[_PyQuoter],
506+
unquoter: type[_PyUnquoter],
508507
text_input: str,
509508
) -> None:
510509
quote = quoter()
@@ -527,8 +526,8 @@ def test_quote_unquote_parameter(
527526
@pytest.mark.parametrize("quoter", quoters, ids=quoter_ids)
528527
@pytest.mark.parametrize("unquoter", unquoters, ids=unquoter_ids)
529528
def test_quote_unquote_parameter_requote(
530-
quoter: Type[_PyQuoter],
531-
unquoter: Type[_PyUnquoter],
529+
quoter: type[_PyQuoter],
530+
unquoter: type[_PyUnquoter],
532531
text_input: str,
533532
) -> None:
534533
quote = quoter(requote=True)
@@ -551,8 +550,8 @@ def test_quote_unquote_parameter_requote(
551550
@pytest.mark.parametrize("quoter", quoters, ids=quoter_ids)
552551
@pytest.mark.parametrize("unquoter", unquoters, ids=unquoter_ids)
553552
def test_quote_unquote_parameter_path_safe(
554-
quoter: Type[_PyQuoter],
555-
unquoter: Type[_PyUnquoter],
553+
quoter: type[_PyQuoter],
554+
unquoter: type[_PyUnquoter],
556555
text_input: str,
557556
) -> None:
558557
quote = quoter()

tests/test_url_query.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Sequence, Tuple
1+
from collections.abc import Sequence
22
from urllib.parse import parse_qs, urlencode
33

44
import pytest
@@ -10,7 +10,7 @@
1010
# Basic chars in query values
1111
# ========================================
1212

13-
URLS_WITH_BASIC_QUERY_VALUES: List[Tuple[URL, MultiDict]] = [
13+
URLS_WITH_BASIC_QUERY_VALUES: list[tuple[URL, MultiDict]] = [
1414
# Empty strings, keys and values
1515
(
1616
URL("http://example.com"),
@@ -88,7 +88,7 @@ def test_query_dont_unqoute_twice():
8888
_SEMICOLON_XFAIL = pytest.mark.xfail(
8989
condition="separator" not in parse_qs.__code__.co_varnames,
9090
reason=(
91-
"Python versions < 3.8.8 and < 3.9.2 lack a fix for "
91+
"Python versions < 3.9.2 lack a fix for "
9292
'CVE-2021-23336 dropping ";" as a valid query parameter separator, '
9393
"making this test fail."
9494
),

yarl/_url.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22
import re
33
import sys
44
import warnings
5-
from collections.abc import Mapping, Sequence
5+
from collections.abc import Iterable, Mapping, Sequence
66
from contextlib import suppress
77
from functools import _CacheInfo, lru_cache
88
from ipaddress import ip_address
99
from typing import (
1010
TYPE_CHECKING,
1111
Any,
12-
Iterable,
13-
List,
1412
SupportsInt,
1513
Tuple,
1614
TypedDict,
@@ -109,34 +107,34 @@ class _InternalURLCache(TypedDict, total=False):
109107
explicit_port: Union[int, None]
110108
raw_path: str
111109
path: str
112-
_parsed_query: List[Tuple[str, str]]
110+
_parsed_query: list[tuple[str, str]]
113111
query: "MultiDictProxy[str]"
114112
raw_query_string: str
115113
query_string: str
116114
path_qs: str
117115
raw_path_qs: str
118116
raw_fragment: str
119117
fragment: str
120-
raw_parts: Tuple[str, ...]
121-
parts: Tuple[str, ...]
118+
raw_parts: tuple[str, ...]
119+
parts: tuple[str, ...]
122120
parent: "URL"
123121
raw_name: str
124122
name: str
125123
raw_suffix: str
126124
suffix: str
127-
raw_suffixes: Tuple[str, ...]
128-
suffixes: Tuple[str, ...]
125+
raw_suffixes: tuple[str, ...]
126+
suffixes: tuple[str, ...]
129127

130128

131129
def rewrite_module(obj: _T) -> _T:
132130
obj.__module__ = "yarl"
133131
return obj
134132

135133

136-
def _normalize_path_segments(segments: "Sequence[str]") -> List[str]:
134+
def _normalize_path_segments(segments: "Sequence[str]") -> list[str]:
137135
"""Drop '.' and '..' from a sequence of str segments"""
138136

139-
resolved_path: List[str] = []
137+
resolved_path: list[str] = []
140138

141139
for seg in segments:
142140
if seg == "..":
@@ -504,7 +502,7 @@ def __bool__(self) -> bool:
504502
val = self._val
505503
return bool(val.netloc or val.path or val.query or val.fragment)
506504

507-
def __getstate__(self) -> Tuple[SplitResult]:
505+
def __getstate__(self) -> tuple[SplitResult]:
508506
return (self._val,)
509507

510508
def __setstate__(self, state):
@@ -786,7 +784,7 @@ def path_safe(self) -> str:
786784
return self._PATH_SAFE_UNQUOTER(self.raw_path)
787785

788786
@cached_property
789-
def _parsed_query(self) -> List[Tuple[str, str]]:
787+
def _parsed_query(self) -> list[tuple[str, str]]:
790788
"""Parse query part of URL."""
791789
return parse_qsl(self._val.query, keep_blank_values=True)
792790

@@ -851,7 +849,7 @@ def fragment(self) -> str:
851849
return self._UNQUOTER(self._val.fragment)
852850

853851
@cached_property
854-
def raw_parts(self) -> Tuple[str, ...]:
852+
def raw_parts(self) -> tuple[str, ...]:
855853
"""A tuple containing encoded *path* parts.
856854
857855
('/',) for absolute URLs if *path* is missing.
@@ -865,7 +863,7 @@ def raw_parts(self) -> Tuple[str, ...]:
865863
return tuple(path.split("/"))
866864

867865
@cached_property
868-
def parts(self) -> Tuple[str, ...]:
866+
def parts(self) -> tuple[str, ...]:
869867
"""A tuple containing decoded *path* parts.
870868
871869
('/',) for absolute URLs if *path* is missing.
@@ -920,15 +918,15 @@ def suffix(self) -> str:
920918
return self._UNQUOTER(self.raw_suffix)
921919

922920
@cached_property
923-
def raw_suffixes(self) -> Tuple[str, ...]:
921+
def raw_suffixes(self) -> tuple[str, ...]:
924922
name = self.raw_name
925923
if name.endswith("."):
926924
return ()
927925
name = name.lstrip(".")
928926
return tuple("." + suffix for suffix in name.split(".")[1:])
929927

930928
@cached_property
931-
def suffixes(self) -> Tuple[str, ...]:
929+
def suffixes(self) -> tuple[str, ...]:
932930
return tuple(self._UNQUOTER(suffix) for suffix in self.raw_suffixes)
933931

934932
@staticmethod
@@ -947,7 +945,7 @@ def _make_child(self, paths: "Sequence[str]", encoded: bool = False) -> "URL":
947945
add paths to self._val.path, accounting for absolute vs relative paths,
948946
keep existing, but do not create new, empty segments
949947
"""
950-
parsed: List[str] = []
948+
parsed: list[str] = []
951949
needs_normalize: bool = False
952950
for idx, path in enumerate(reversed(paths)):
953951
# empty segment of last is not removed
@@ -995,7 +993,7 @@ def _normalize_path(cls, path: str) -> str:
995993
@lru_cache # match the same size as urlsplit
996994
def _parse_host(
997995
cls, host: str
998-
) -> Tuple[bool, str, Union[bool, None], str, str, str]:
996+
) -> tuple[bool, str, Union[bool, None], str, str, str]:
999997
"""Parse host into parts
1000998
1001999
Returns a tuple of:
@@ -1111,7 +1109,7 @@ def _make_netloc(
11111109
def _split_netloc(
11121110
cls,
11131111
netloc: str,
1114-
) -> Tuple[Union[str, None], Union[str, None], Union[str, None], Union[int, None]]:
1112+
) -> tuple[Union[str, None], Union[str, None], Union[str, None], Union[int, None]]:
11151113
"""Split netloc into username, password, host and port."""
11161114
if "@" not in netloc:
11171115
username: Union[str, None] = None
@@ -1253,7 +1251,7 @@ def with_path(self, path: str, *, encoded: bool = False) -> "URL":
12531251

12541252
def _get_str_query_from_sequence_iterable(
12551253
self,
1256-
items: Iterable[Tuple[Union[str, istr], QueryVariable]],
1254+
items: Iterable[tuple[Union[str, istr], QueryVariable]],
12571255
) -> str:
12581256
"""Return a query string from a sequence of (key, value) pairs.
12591257
@@ -1299,7 +1297,7 @@ def _query_var(v: QueryVariable) -> str:
12991297
)
13001298

13011299
def _get_str_query_from_iterable(
1302-
self, items: Iterable[Tuple[Union[str, istr], str]]
1300+
self, items: Iterable[tuple[Union[str, istr], str]]
13031301
) -> str:
13041302
"""Return a query string from an iterable.
13051303
@@ -1622,7 +1620,7 @@ def _idna_encode(host: str) -> str:
16221620

16231621

16241622
@lru_cache(_MAXCACHE)
1625-
def _ip_compressed_version(raw_ip: str) -> Tuple[str, int]:
1623+
def _ip_compressed_version(raw_ip: str) -> tuple[str, int]:
16261624
"""Return compressed version of IP address and its version."""
16271625
ip = ip_address(raw_ip)
16281626
return ip.compressed, ip.version

0 commit comments

Comments
 (0)