Skip to content

Commit 169a8f1

Browse files
authored
Drop Support for Python 3.8 & 3.9 (#3774)
* Drop 3.8 and 3.9 from CI, run pyupgrade tool for 3.8 -> 3.9 * Move from 3.9 -> 3.10 * Add newsfragment
1 parent 231877c commit 169a8f1

File tree

102 files changed

+1327
-1664
lines changed

Some content is hidden

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

102 files changed

+1327
-1664
lines changed

.circleci/config.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ workflows:
221221
- common:
222222
matrix:
223223
parameters:
224-
python_minor_version: ["8", "9", "10", "11", "12", "13"]
224+
python_minor_version: ["10", "11", "12", "13"]
225225
tox_env: [
226226
"lint",
227227
"core",
@@ -234,7 +234,7 @@ workflows:
234234
- geth:
235235
matrix:
236236
parameters:
237-
python_minor_version: ["8", "9", "10", "11", "12", "13"]
237+
python_minor_version: ["10", "11", "12", "13"]
238238
tox_env: [
239239
"integration-goethereum-ipc",
240240
"integration-goethereum-ipc_async",
@@ -247,7 +247,7 @@ workflows:
247247
- docs:
248248
matrix:
249249
parameters:
250-
python_minor_version: ["9"]
250+
python_minor_version: ["10"]
251251
name: "py3<< matrix.python_minor_version >>-docs"
252252
- windows-wheel:
253253
matrix:

.project-template/refill_template_vars.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def main():
1111
template_vars_file = template_dir / "template_vars.txt"
1212
fill_template_vars_script = template_dir / "fill_template_vars.py"
1313

14-
with open(template_vars_file, "r") as input_file:
14+
with open(template_vars_file) as input_file:
1515
content_lines = input_file.readlines()
1616

1717
process = subprocess.Popen(

README.md

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

1111
web3.py allows you to interact with the Ethereum blockchain using Python, enabling you to build decentralized applications, interact with smart contracts, and much more.
1212

13-
- Python 3.8+ support
13+
- Python 3.10+ support
1414

1515
## Installation
1616

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import os
1818

1919
DIR = os.path.dirname(__file__)
20-
with open(os.path.join(DIR, "../setup.py"), "r") as f:
20+
with open(os.path.join(DIR, "../setup.py")) as f:
2121
for line in f:
2222
if "version=" in line:
2323
setup_version = line.split('"')[1]

ens/_normalization.py

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@
55
import os
66
from typing import (
77
Any,
8-
Dict,
9-
List,
108
Literal,
11-
Optional,
12-
Set,
13-
Tuple,
14-
Union,
159
)
1610

1711
from pyunormalize import (
@@ -27,9 +21,9 @@
2721

2822

2923
def _json_list_mapping_to_dict(
30-
f: Dict[str, Any],
24+
f: dict[str, Any],
3125
list_mapped_key: str,
32-
) -> Dict[str, Any]:
26+
) -> dict[str, Any]:
3327
"""
3428
Takes a `[key, [value]]` mapping from the original ENS spec json files and turns it
3529
into a `{key: value}` mapping.
@@ -67,17 +61,17 @@ class TokenType(Enum):
6761
class Token:
6862
type: Literal[TokenType.TEXT, TokenType.EMOJI]
6963
_original_text: str
70-
_original_codepoints: List[int]
71-
_normalized_codepoints: Optional[List[int]] = None
64+
_original_codepoints: list[int]
65+
_normalized_codepoints: list[int] | None = None
7266

7367
restricted: bool = False
7468

75-
def __init__(self, codepoints: List[int]) -> None:
69+
def __init__(self, codepoints: list[int]) -> None:
7670
self._original_codepoints = codepoints
7771
self._original_text = "".join(chr(cp) for cp in codepoints)
7872

7973
@property
80-
def codepoints(self) -> List[int]:
74+
def codepoints(self) -> list[int]:
8175
return (
8276
self._normalized_codepoints
8377
if self._normalized_codepoints
@@ -99,12 +93,12 @@ class TextToken(Token):
9993

10094
class Label:
10195
type: str
102-
tokens: List[Token]
96+
tokens: list[Token]
10397

10498
def __init__(
10599
self,
106100
type: str = None,
107-
tokens: List[Token] = None,
101+
tokens: list[Token] = None,
108102
) -> None:
109103
self.type = type
110104
self.tokens = tokens
@@ -118,9 +112,9 @@ def text(self) -> str:
118112

119113

120114
class ENSNormalizedName:
121-
labels: List[Label]
115+
labels: list[Label]
122116

123-
def __init__(self, normalized_labels: List[Label]) -> None:
117+
def __init__(self, normalized_labels: list[Label]) -> None:
124118
self.labels = normalized_labels
125119

126120
@property
@@ -140,28 +134,28 @@ def as_text(self) -> str:
140134
}
141135

142136

143-
def _extract_valid_codepoints() -> Set[int]:
137+
def _extract_valid_codepoints() -> set[int]:
144138
all_valid = set()
145139
for _name, valid_cps in VALID_BY_GROUPS.items():
146140
all_valid.update(valid_cps)
147141
all_valid.update(map(ord, NFD("".join(map(chr, all_valid)))))
148142
return all_valid
149143

150144

151-
def _construct_whole_confusable_map() -> Dict[int, Set[str]]:
145+
def _construct_whole_confusable_map() -> dict[int, set[str]]:
152146
"""
153147
Create a mapping, per confusable, that contains all the groups in the cp's whole
154148
confusable excluding the confusable extent of the cp itself - as per the spec at
155149
https://docs.ens.domains/ens-improvement-proposals/ensip-15-normalization-standard
156150
"""
157-
whole_map: Dict[int, Set[str]] = {}
151+
whole_map: dict[int, set[str]] = {}
158152
for whole in NORMALIZATION_SPEC["wholes"]:
159-
whole_confusables: Set[int] = set(whole["valid"] + whole["confused"])
160-
confusable_extents: List[Tuple[Set[int], Set[str]]] = []
153+
whole_confusables: set[int] = set(whole["valid"] + whole["confused"])
154+
confusable_extents: list[tuple[set[int], set[str]]] = []
161155

162156
for confusable_cp in whole_confusables:
163157
# create confusable extents for all whole confusables
164-
groups: Set[str] = set()
158+
groups: set[str] = set()
165159
for gn, gv in VALID_BY_GROUPS.items():
166160
if confusable_cp in gv:
167161
groups.add(gn)
@@ -181,7 +175,7 @@ def _construct_whole_confusable_map() -> Dict[int, Set[str]]:
181175
confusable_extents.append(({confusable_cp}, groups))
182176

183177
for confusable_cp in whole_confusables:
184-
confusable_cp_extent_groups: Set[str] = set()
178+
confusable_cp_extent_groups: set[str] = set()
185179

186180
if confusable_cp in whole["confused"]:
187181
whole_map[confusable_cp] = set()
@@ -209,13 +203,13 @@ def _is_fenced(cp: int) -> bool:
209203
return cp in [fenced[0] for fenced in NORMALIZATION_SPEC["fenced"]]
210204

211205

212-
def _codepoints_to_text(cps: Union[List[List[int]], List[int]]) -> str:
206+
def _codepoints_to_text(cps: list[list[int]] | list[int]) -> str:
213207
return "".join(
214208
chr(cp) if isinstance(cp, int) else _codepoints_to_text(cp) for cp in cps
215209
)
216210

217211

218-
def _validate_tokens_and_get_label_type(tokens: List[Token]) -> str:
212+
def _validate_tokens_and_get_label_type(tokens: list[Token]) -> str:
219213
"""
220214
Validate tokens and return the label type.
221215
@@ -388,7 +382,7 @@ def _validate_tokens_and_get_label_type(tokens: List[Token]) -> str:
388382
return chars_group_name
389383

390384

391-
def _build_and_validate_label_from_tokens(tokens: List[Token]) -> Label:
385+
def _build_and_validate_label_from_tokens(tokens: list[Token]) -> Label:
392386
for token in tokens:
393387
if token.type == TokenType.TEXT:
394388
# apply NFC normalization to text tokens
@@ -404,7 +398,7 @@ def _build_and_validate_label_from_tokens(tokens: List[Token]) -> Label:
404398
return label
405399

406400

407-
def _buffer_codepoints_to_chars(buffer: Union[List[int], List[List[int]]]) -> str:
401+
def _buffer_codepoints_to_chars(buffer: list[int] | list[list[int]]) -> str:
408402
return "".join(
409403
"".join(chr(c) for c in char) if isinstance(char, list) else chr(char)
410404
for char in buffer
@@ -438,8 +432,8 @@ def normalize_name_ensip15(name: str) -> ENSNormalizedName:
438432
# _input takes the label and breaks it into a list of unicode code points
439433
# e.g. "xyz👨🏻" -> [120, 121, 122, 128104, 127995]
440434
_input = [ord(c) for c in label_str]
441-
buffer: List[int] = []
442-
tokens: List[Token] = []
435+
buffer: list[int] = []
436+
tokens: list[Token] = []
443437

444438
while len(_input) > 0:
445439
emoji_codepoint = None

ens/async_ens.py

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
Coroutine,
88
Optional,
99
Sequence,
10-
Tuple,
11-
Union,
1210
cast,
1311
)
1412

@@ -103,8 +101,8 @@ class AsyncENS(BaseENS):
103101
def __init__(
104102
self,
105103
provider: Optional["AsyncBaseProvider"] = None,
106-
addr: Optional[ChecksumAddress] = None,
107-
middleware: Optional[Sequence[Tuple["Middleware", str]]] = None,
104+
addr: ChecksumAddress | None = None,
105+
middleware: Sequence[tuple["Middleware", str]] | None = None,
108106
) -> None:
109107
"""
110108
:param provider: a single provider used to connect to Ethereum
@@ -137,7 +135,11 @@ def from_web3(
137135
"""
138136
provider = w3.manager.provider
139137
middleware = w3.middleware_onion.middleware
140-
ns = cls(cast("AsyncBaseProvider", provider), addr=addr, middleware=middleware)
138+
ns = cls(
139+
cast("AsyncBaseProvider", provider),
140+
addr=addr,
141+
middleware=middleware,
142+
)
141143

142144
# inherit strict bytes checking from w3 instance
143145
ns.strict_bytes_type_checking = w3.strict_bytes_type_checking
@@ -147,8 +149,8 @@ def from_web3(
147149
async def address(
148150
self,
149151
name: str,
150-
coin_type: Optional[int] = None,
151-
) -> Optional[ChecksumAddress]:
152+
coin_type: int | None = None,
153+
) -> ChecksumAddress | None:
152154
"""
153155
Look up the Ethereum address that `name` currently points to.
154156
@@ -163,7 +165,10 @@ async def address(
163165
else:
164166
r = await self.resolver(name)
165167
await _async_validate_resolver_and_interface_id(
166-
name, r, ENS_MULTICHAIN_ADDRESS_INTERFACE_ID, "addr(bytes32,uint256)"
168+
name,
169+
r,
170+
ENS_MULTICHAIN_ADDRESS_INTERFACE_ID,
171+
"addr(bytes32,uint256)",
167172
)
168173
node = raw_name_to_hash(name)
169174
address_as_bytes = await r.caller.addr(node, coin_type)
@@ -174,12 +179,12 @@ async def address(
174179
async def setup_address(
175180
self,
176181
name: str,
177-
address: Union[Address, ChecksumAddress, HexAddress] = cast( # noqa: B008
178-
ChecksumAddress, default
179-
),
180-
coin_type: Optional[int] = None,
182+
address: Address
183+
| ChecksumAddress
184+
| HexAddress = cast(ChecksumAddress, default), # noqa: B008
185+
coin_type: int | None = None,
181186
transact: Optional["TxParams"] = None,
182-
) -> Optional[HexBytes]:
187+
) -> HexBytes | None:
183188
"""
184189
Set up the name to point to the supplied address.
185190
The sender of the transaction must own the name, or
@@ -228,7 +233,7 @@ async def setup_address(
228233
transact
229234
)
230235

231-
async def name(self, address: ChecksumAddress) -> Optional[str]:
236+
async def name(self, address: ChecksumAddress) -> str | None:
232237
"""
233238
Look up the name that the address points to, using a
234239
reverse lookup. Reverse lookup is opt-in for name owners.
@@ -248,7 +253,7 @@ async def name(self, address: ChecksumAddress) -> Optional[str]:
248253
async def setup_name(
249254
self,
250255
name: str,
251-
address: Optional[ChecksumAddress] = None,
256+
address: ChecksumAddress | None = None,
252257
transact: Optional["TxParams"] = None,
253258
) -> HexBytes:
254259
"""
@@ -314,7 +319,7 @@ async def setup_owner(
314319
name: str,
315320
new_owner: ChecksumAddress = None,
316321
transact: Optional["TxParams"] = None,
317-
) -> Optional[ChecksumAddress]:
322+
) -> ChecksumAddress | None:
318323
"""
319324
Set the owner of the supplied name to `new_owner`.
320325
@@ -437,7 +442,7 @@ async def _get_resolver(
437442
self,
438443
normal_name: str,
439444
fn_name: str = "addr",
440-
) -> Tuple[Optional["AsyncContract"], str]:
445+
) -> tuple[Optional["AsyncContract"], str]:
441446
current_name = normal_name
442447

443448
# look for a resolver, starting at the full name and taking the
@@ -454,7 +459,8 @@ async def _get_resolver(
454459
if not is_none_or_zero_address(resolver_addr):
455460
# if resolver found, return it
456461
resolver = cast(
457-
"AsyncContract", self._type_aware_resolver(resolver_addr, fn_name)
462+
"AsyncContract",
463+
self._type_aware_resolver(resolver_addr, fn_name),
458464
)
459465
return resolver, current_name
460466

@@ -464,7 +470,7 @@ async def _get_resolver(
464470
async def _set_resolver(
465471
self,
466472
name: str,
467-
resolver_addr: Optional[ChecksumAddress] = None,
473+
resolver_addr: ChecksumAddress | None = None,
468474
transact: Optional["TxParams"] = None,
469475
) -> "AsyncContract":
470476
if not transact:
@@ -487,7 +493,7 @@ async def _resolve(
487493
self,
488494
name: str,
489495
fn_name: str = "addr",
490-
) -> Optional[Union[ChecksumAddress, str]]:
496+
) -> ChecksumAddress | str | None:
491497
normal_name = normalize_name(name)
492498

493499
resolver, current_name = await self._get_resolver(normal_name, fn_name)
@@ -523,7 +529,7 @@ async def _assert_control(
523529
self,
524530
account: ChecksumAddress,
525531
name: str,
526-
parent_owned: Optional[str] = None,
532+
parent_owned: str | None = None,
527533
) -> None:
528534
if not address_in(account, await self.w3.eth.accounts):
529535
raise UnauthorizedError(
@@ -533,7 +539,7 @@ async def _assert_control(
533539

534540
async def _first_owner(
535541
self, name: str
536-
) -> Tuple[Optional[ChecksumAddress], Sequence[str], str]:
542+
) -> tuple[ChecksumAddress | None, Sequence[str], str]:
537543
"""
538544
Takes a name, and returns the owner of the deepest subdomain that has an owner
539545
@@ -554,7 +560,7 @@ async def _claim_ownership(
554560
owner: ChecksumAddress,
555561
unowned: Sequence[str],
556562
owned: str,
557-
old_owner: Optional[ChecksumAddress] = None,
563+
old_owner: ChecksumAddress | None = None,
558564
transact: Optional["TxParams"] = None,
559565
) -> None:
560566
if not transact:
@@ -575,7 +581,7 @@ async def _claim_ownership(
575581

576582
async def _setup_reverse(
577583
self,
578-
name: Optional[str],
584+
name: str | None,
579585
address: ChecksumAddress,
580586
transact: Optional["TxParams"] = None,
581587
) -> HexBytes:

0 commit comments

Comments
 (0)