Skip to content

Commit 551c657

Browse files
spazmcclauss
andauthored
[Mypy] fix other/least_recently_used (TheAlgorithms#5814)
* makes LRUCache constructor concrete * fixes bug in dq_removal in other/least_recently_used + deque.remove() operates by value not index * [mypy] Annotates other/least_recently_used over generic type + clean-up: rename key_reference to match type. * [mypy] updates example to demonstrate LRUCache with complex type * Adds doctest to other/least_recently_used * mypy.ini: Remove exclude = (other/least_recently_used.py) * Various mypy configs * Delete mypy.ini * Add mypy to .pre-commit-config.yaml * mypy --ignore-missing-imports --install-types --non-interactive . * mypy v0.910 * Pillow=8.3.7 * Pillow==8.3.7 * Pillow==8.3.2 * Update .pre-commit-config.yaml * Update requirements.txt * Update pre-commit.yml * --install-types # See mirrors-mypy README.md Co-authored-by: Christian Clauss <[email protected]>
1 parent 9b9405f commit 551c657

File tree

6 files changed

+68
-35
lines changed

6 files changed

+68
-35
lines changed

.github/workflows/build.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
run: |
2222
python -m pip install --upgrade pip setuptools six wheel
2323
python -m pip install mypy pytest-cov -r requirements.txt
24-
- run: mypy . # See `mypy.ini` for configuration settings.
24+
- run: mypy --ignore-missing-imports --install-types --non-interactive .
2525
- name: Run tests
2626
run: pytest --doctest-modules --ignore=project_euler/ --ignore=scripts/validate_solutions.py --cov-report=term-missing:skip-covered --cov=. .
2727
- if: ${{ success() }}

.github/workflows/pre-commit.yml

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ jobs:
1414
~/.cache/pip
1515
key: ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
1616
- uses: actions/setup-python@v2
17+
with:
18+
python-version: 3.9
1719
- uses: psf/[email protected]
1820
- name: Install pre-commit
1921
run: |

.pre-commit-config.yaml

+15-8
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,26 @@ repos:
1212
data_structures/heap/binomial_heap.py
1313
)$
1414
- id: requirements-txt-fixer
15+
1516
- repo: https://github.com/psf/black
1617
rev: 21.4b0
1718
hooks:
1819
- id: black
20+
1921
- repo: https://github.com/PyCQA/isort
2022
rev: 5.8.0
2123
hooks:
2224
- id: isort
2325
args:
2426
- --profile=black
27+
2528
- repo: https://github.com/asottile/pyupgrade
2629
rev: v2.29.0
2730
hooks:
2831
- id: pyupgrade
2932
args:
3033
- --py39-plus
34+
3135
- repo: https://gitlab.com/pycqa/flake8
3236
rev: 3.9.1
3337
hooks:
@@ -36,27 +40,30 @@ repos:
3640
- --ignore=E203,W503
3741
- --max-complexity=25
3842
- --max-line-length=88
39-
# FIXME: fix mypy errors and then uncomment this
40-
# - repo: https://github.com/pre-commit/mirrors-mypy
41-
# rev: v0.782
42-
# hooks:
43-
# - id: mypy
44-
# args:
45-
# - --ignore-missing-imports
43+
44+
- repo: https://github.com/pre-commit/mirrors-mypy
45+
rev: v0.910
46+
hooks:
47+
- id: mypy
48+
args:
49+
- --ignore-missing-imports
50+
- --install-types # See mirrors-mypy README.md
51+
- --non-interactive
52+
4653
- repo: https://github.com/codespell-project/codespell
4754
rev: v2.0.0
4855
hooks:
4956
- id: codespell
5057
args:
5158
- --ignore-words-list=ans,crate,fo,followings,hist,iff,mater,secant,som,tim
5259
- --skip="./.*,./strings/dictionary.txt,./strings/words.txt,./project_euler/problem_022/p022_names.txt"
53-
- --quiet-level=2
5460
exclude: |
5561
(?x)^(
5662
strings/dictionary.txt |
5763
strings/words.txt |
5864
project_euler/problem_022/p022_names.txt
5965
)$
66+
6067
- repo: local
6168
hooks:
6269
- id: validate-filenames

mypy.ini

-5
This file was deleted.

other/least_recently_used.py

+50-20
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,92 @@
1+
from __future__ import annotations
2+
13
import sys
24
from collections import deque
5+
from typing import Generic, TypeVar
6+
7+
T = TypeVar("T")
8+
9+
10+
class LRUCache(Generic[T]):
11+
"""
12+
Page Replacement Algorithm, Least Recently Used (LRU) Caching.
13+
14+
>>> lru_cache: LRUCache[str | int] = LRUCache(4)
15+
>>> lru_cache.refer("A")
16+
>>> lru_cache.refer(2)
17+
>>> lru_cache.refer(3)
18+
19+
>>> lru_cache
20+
LRUCache(4) => [3, 2, 'A']
321
22+
>>> lru_cache.refer("A")
23+
>>> lru_cache
24+
LRUCache(4) => ['A', 3, 2]
425
5-
class LRUCache:
6-
"""Page Replacement Algorithm, Least Recently Used (LRU) Caching."""
26+
>>> lru_cache.refer(4)
27+
>>> lru_cache.refer(5)
28+
>>> lru_cache
29+
LRUCache(4) => [5, 4, 'A', 3]
730
8-
dq_store = object() # Cache store of keys
9-
key_reference_map = object() # References of the keys in cache
31+
"""
32+
33+
dq_store: deque[T] # Cache store of keys
34+
key_reference: set[T] # References of the keys in cache
1035
_MAX_CAPACITY: int = 10 # Maximum capacity of cache
1136

12-
def __init__(self, n: int):
37+
def __init__(self, n: int) -> None:
1338
"""Creates an empty store and map for the keys.
1439
The LRUCache is set the size n.
1540
"""
1641
self.dq_store = deque()
17-
self.key_reference_map = set()
42+
self.key_reference = set()
1843
if not n:
1944
LRUCache._MAX_CAPACITY = sys.maxsize
2045
elif n < 0:
2146
raise ValueError("n should be an integer greater than 0.")
2247
else:
2348
LRUCache._MAX_CAPACITY = n
2449

25-
def refer(self, x):
50+
def refer(self, x: T) -> None:
2651
"""
2752
Looks for a page in the cache store and adds reference to the set.
2853
Remove the least recently used key if the store is full.
2954
Update store to reflect recent access.
3055
"""
31-
if x not in self.key_reference_map:
56+
if x not in self.key_reference:
3257
if len(self.dq_store) == LRUCache._MAX_CAPACITY:
3358
last_element = self.dq_store.pop()
34-
self.key_reference_map.remove(last_element)
59+
self.key_reference.remove(last_element)
3560
else:
36-
index_remove = 0
37-
for idx, key in enumerate(self.dq_store):
38-
if key == x:
39-
index_remove = idx
40-
break
41-
self.dq_store.remove(index_remove)
61+
self.dq_store.remove(x)
4262

4363
self.dq_store.appendleft(x)
44-
self.key_reference_map.add(x)
64+
self.key_reference.add(x)
4565

46-
def display(self):
66+
def display(self) -> None:
4767
"""
4868
Prints all the elements in the store.
4969
"""
5070
for k in self.dq_store:
5171
print(k)
5272

73+
def __repr__(self) -> str:
74+
return f"LRUCache({self._MAX_CAPACITY}) => {list(self.dq_store)}"
75+
5376

5477
if __name__ == "__main__":
55-
lru_cache = LRUCache(4)
56-
lru_cache.refer(1)
78+
import doctest
79+
80+
doctest.testmod()
81+
82+
lru_cache: LRUCache[str | int] = LRUCache(4)
83+
lru_cache.refer("A")
5784
lru_cache.refer(2)
5885
lru_cache.refer(3)
59-
lru_cache.refer(1)
86+
lru_cache.refer("A")
6087
lru_cache.refer(4)
6188
lru_cache.refer(5)
6289
lru_cache.display()
90+
91+
print(lru_cache)
92+
assert str(lru_cache) == "LRUCache(4) => [5, 4, 'A', 3]"

requirements.txt

-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,4 @@ sympy
1616
tensorflow
1717
texttable
1818
tweepy
19-
types-requests
2019
xgboost

0 commit comments

Comments
 (0)