Skip to content

Commit e2ebb76

Browse files
committed
fix: compatibility with python 3.9+ generics and strict type hints
1 parent 8ee8cda commit e2ebb76

File tree

6 files changed

+29
-31
lines changed

6 files changed

+29
-31
lines changed

data_structures/hashing/coalesced_hashing.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
"""
33
Coalesced hashing (hybrid of open addressing + chaining inside the table).
44
5-
Reference: https://en.wikipedia.org/wiki/Hash_table#Coalesced_hashing
5+
Reference: [https://en.wikipedia.org/wiki/Hash_table#Coalesced_hashing](https://en.wikipedia.org/wiki/Hash_table#Coalesced_hashing)
66
"""
77

88
from __future__ import annotations
99

1010
from collections.abc import Iterator, MutableMapping
1111
from dataclasses import dataclass
12-
from typing import TypeVar
12+
from typing import Generic, TypeVar
1313

1414
KEY = TypeVar("KEY")
1515
VAL = TypeVar("VAL")
1616

1717

1818
@dataclass(slots=True)
19-
class _Node[KEY, VAL]:
19+
class _Node(Generic[KEY, VAL]): # noqa: UP046
2020
key: KEY
2121
val: VAL
2222
next: int # -1 means end of chain
@@ -83,18 +83,18 @@ def __setitem__(self, key: KEY, val: VAL) -> None:
8383
# Search chain for update.
8484
cur = home
8585
while True:
86-
n = self._table[cur]
87-
if n is None:
86+
# Explicitly type the current node to satisfy mypy
87+
current_node = self._table[cur]
88+
if current_node is None:
89+
# Should not happen if logic is correct, but handles None safety
8890
break
89-
# FIX: Ensure n is not None before access
90-
assert n is not None
9191

92-
if n.key == key:
93-
n.val = val
92+
if current_node.key == key:
93+
current_node.val = val
9494
return
95-
if n.next == -1:
95+
if current_node.next == -1:
9696
break
97-
cur = n.next
97+
cur = current_node.next
9898

9999
# Insert new node at a free slot and link it.
100100
free = self._find_free_from_end()
@@ -105,10 +105,10 @@ def __setitem__(self, key: KEY, val: VAL) -> None:
105105

106106
self._table[free] = _Node(key, val, -1)
107107

108-
# FIX: Ensure we are linking from a valid node
108+
# Link the previous end of chain to the new free slot
109+
# We re-fetch the node at 'cur' to be safe
109110
if (tail_node := self._table[cur]) is not None:
110111
tail_node.next = free
111-
112112
self._len += 1
113113

114114
def __getitem__(self, key: KEY) -> VAL:
@@ -118,7 +118,6 @@ def __getitem__(self, key: KEY) -> VAL:
118118
node = self._table[cur]
119119
if node is None:
120120
break
121-
assert node is not None
122121
if node.key == key:
123122
return node.val
124123
cur = node.next
@@ -133,7 +132,6 @@ def __delitem__(self, key: KEY) -> None:
133132
node = self._table[cur]
134133
if node is None:
135134
break
136-
assert node is not None
137135
if node.key == key:
138136
# If deleting head: copy next node into home if exists
139137
# (keeps chains valid).
@@ -142,17 +140,17 @@ def __delitem__(self, key: KEY) -> None:
142140
self._table[cur] = None
143141
else:
144142
nxt = node.next
145-
# Safely copy next node data
146-
nxt_node = self._table[nxt]
147-
# Mypy needs to know nxt_node exists if we are copying from it
148-
if nxt_node is not None:
143+
next_node = self._table[nxt]
144+
# Must assert next_node is not None for mypy
145+
if next_node is not None:
149146
self._table[cur] = _Node(
150-
nxt_node.key,
151-
nxt_node.val,
152-
nxt_node.next,
147+
next_node.key,
148+
next_node.val,
149+
next_node.next,
153150
)
154151
self._table[nxt] = None
155152
else:
153+
# Update previous node's next pointer
156154
prev_node = self._table[prev]
157155
if prev_node is not None:
158156
prev_node.next = node.next

data_structures/hashing/fnv_hashtable.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from collections.abc import Iterator, MutableMapping
1212
from dataclasses import dataclass
13-
from typing import TypeVar
13+
from typing import Generic, TypeVar
1414

1515
KEY = TypeVar("KEY")
1616
VAL = TypeVar("VAL")
@@ -47,7 +47,7 @@ def fnv1a_64(data: bytes) -> int:
4747

4848

4949
@dataclass(slots=True)
50-
class _Item[KEY, VAL]:
50+
class _Item(Generic[KEY, VAL]): # noqa: UP046
5151
key: KEY
5252
val: VAL
5353

data_structures/hashing/hopscotch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111

1212
from collections.abc import Iterator, MutableMapping
1313
from dataclasses import dataclass
14-
from typing import TypeVar
14+
from typing import Generic, TypeVar
1515

1616
KEY = TypeVar("KEY")
1717
VAL = TypeVar("VAL")
1818

1919

2020
@dataclass(slots=True)
21-
class _Item[KEY, VAL]:
21+
class _Item(Generic[KEY, VAL]): # noqa: UP046
2222
key: KEY
2323
val: VAL
2424

data_structures/hashing/linear_probing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class LinearProbing(HashTable):
1616
Hash function: h(k, i) = (h(k) + i) % m
1717
"""
1818

19-
def __init__(self, *args, **kwargs):
19+
def __init__(self, *args: Any, **kwargs: Any) -> None:
2020
super().__init__(*args, **kwargs)
2121

2222
def _collision_resolution(self, key: int, data: Any = None) -> int | None:

data_structures/hashing/power_of_two.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from collections.abc import Iterator, MutableMapping
1515
from dataclasses import dataclass
16-
from typing import TypeVar
16+
from typing import Generic, TypeVar
1717

1818
KEY = TypeVar("KEY")
1919
VAL = TypeVar("VAL")
@@ -38,7 +38,7 @@ def _mix_hash(h: int) -> int:
3838

3939

4040
@dataclass(slots=True)
41-
class _Item[KEY, VAL]:
41+
class _Item(Generic[KEY, VAL]): # noqa: UP046
4242
key: KEY
4343
val: VAL
4444

data_structures/hashing/robin_hood.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99

1010
from collections.abc import Iterator, MutableMapping
1111
from dataclasses import dataclass
12-
from typing import TypeVar
12+
from typing import Generic, TypeVar
1313

1414
KEY = TypeVar("KEY")
1515
VAL = TypeVar("VAL")
1616

1717

1818
@dataclass(slots=True)
19-
class _Entry[KEY, VAL]:
19+
class _Entry(Generic[KEY, VAL]): # noqa: UP046
2020
key: KEY
2121
val: VAL
2222
psl: int # probe sequence length (distance from home)

0 commit comments

Comments
 (0)