diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e5f8d6b39a7b..df000cda5997 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: run: | python -m pip install --upgrade pip setuptools six wheel python -m pip install mypy pytest-cov -r requirements.txt - - run: mypy . # See `mypy.ini` for configuration settings. + - run: mypy --ignore-missing-imports --install-types --non-interactive . - name: Run tests run: pytest --doctest-modules --ignore=project_euler/ --ignore=scripts/validate_solutions.py --cov-report=term-missing:skip-covered --cov=. . - if: ${{ success() }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 27a5a97c0b6c..19196098b1c1 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -14,6 +14,8 @@ jobs: ~/.cache/pip key: ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} - uses: actions/setup-python@v2 + with: + python-version: 3.9 - uses: psf/black@21.4b0 - name: Install pre-commit run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e60003051365..0ebd6dfa0d7e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,22 +12,26 @@ repos: data_structures/heap/binomial_heap.py )$ - id: requirements-txt-fixer + - repo: https://github.com/psf/black rev: 21.4b0 hooks: - id: black + - repo: https://github.com/PyCQA/isort rev: 5.8.0 hooks: - id: isort args: - --profile=black + - repo: https://github.com/asottile/pyupgrade rev: v2.29.0 hooks: - id: pyupgrade args: - --py39-plus + - repo: https://gitlab.com/pycqa/flake8 rev: 3.9.1 hooks: @@ -36,13 +40,16 @@ repos: - --ignore=E203,W503 - --max-complexity=25 - --max-line-length=88 -# FIXME: fix mypy errors and then uncomment this -# - repo: https://github.com/pre-commit/mirrors-mypy -# rev: v0.782 -# hooks: -# - id: mypy -# args: -# - --ignore-missing-imports + + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.910 + hooks: + - id: mypy + args: + - --ignore-missing-imports + - --install-types # See mirrors-mypy README.md + - --non-interactive + - repo: https://github.com/codespell-project/codespell rev: v2.0.0 hooks: @@ -50,13 +57,13 @@ repos: args: - --ignore-words-list=ans,crate,fo,followings,hist,iff,mater,secant,som,tim - --skip="./.*,./strings/dictionary.txt,./strings/words.txt,./project_euler/problem_022/p022_names.txt" - - --quiet-level=2 exclude: | (?x)^( strings/dictionary.txt | strings/words.txt | project_euler/problem_022/p022_names.txt )$ + - repo: local hooks: - id: validate-filenames diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 7dbc7c4ffc80..000000000000 --- a/mypy.ini +++ /dev/null @@ -1,5 +0,0 @@ -[mypy] -ignore_missing_imports = True -install_types = True -non_interactive = True -exclude = (other/least_recently_used.py) diff --git a/other/least_recently_used.py b/other/least_recently_used.py index 9d6b6d7cb6a6..cb692bb1b1c0 100644 --- a/other/least_recently_used.py +++ b/other/least_recently_used.py @@ -1,20 +1,45 @@ +from __future__ import annotations + import sys from collections import deque +from typing import Generic, TypeVar + +T = TypeVar("T") + + +class LRUCache(Generic[T]): + """ + Page Replacement Algorithm, Least Recently Used (LRU) Caching. + + >>> lru_cache: LRUCache[str | int] = LRUCache(4) + >>> lru_cache.refer("A") + >>> lru_cache.refer(2) + >>> lru_cache.refer(3) + + >>> lru_cache + LRUCache(4) => [3, 2, 'A'] + >>> lru_cache.refer("A") + >>> lru_cache + LRUCache(4) => ['A', 3, 2] -class LRUCache: - """Page Replacement Algorithm, Least Recently Used (LRU) Caching.""" + >>> lru_cache.refer(4) + >>> lru_cache.refer(5) + >>> lru_cache + LRUCache(4) => [5, 4, 'A', 3] - dq_store = object() # Cache store of keys - key_reference_map = object() # References of the keys in cache + """ + + dq_store: deque[T] # Cache store of keys + key_reference: set[T] # References of the keys in cache _MAX_CAPACITY: int = 10 # Maximum capacity of cache - def __init__(self, n: int): + def __init__(self, n: int) -> None: """Creates an empty store and map for the keys. The LRUCache is set the size n. """ self.dq_store = deque() - self.key_reference_map = set() + self.key_reference = set() if not n: LRUCache._MAX_CAPACITY = sys.maxsize elif n < 0: @@ -22,41 +47,46 @@ def __init__(self, n: int): else: LRUCache._MAX_CAPACITY = n - def refer(self, x): + def refer(self, x: T) -> None: """ Looks for a page in the cache store and adds reference to the set. Remove the least recently used key if the store is full. Update store to reflect recent access. """ - if x not in self.key_reference_map: + if x not in self.key_reference: if len(self.dq_store) == LRUCache._MAX_CAPACITY: last_element = self.dq_store.pop() - self.key_reference_map.remove(last_element) + self.key_reference.remove(last_element) else: - index_remove = 0 - for idx, key in enumerate(self.dq_store): - if key == x: - index_remove = idx - break - self.dq_store.remove(index_remove) + self.dq_store.remove(x) self.dq_store.appendleft(x) - self.key_reference_map.add(x) + self.key_reference.add(x) - def display(self): + def display(self) -> None: """ Prints all the elements in the store. """ for k in self.dq_store: print(k) + def __repr__(self) -> str: + return f"LRUCache({self._MAX_CAPACITY}) => {list(self.dq_store)}" + if __name__ == "__main__": - lru_cache = LRUCache(4) - lru_cache.refer(1) + import doctest + + doctest.testmod() + + lru_cache: LRUCache[str | int] = LRUCache(4) + lru_cache.refer("A") lru_cache.refer(2) lru_cache.refer(3) - lru_cache.refer(1) + lru_cache.refer("A") lru_cache.refer(4) lru_cache.refer(5) lru_cache.display() + + print(lru_cache) + assert str(lru_cache) == "LRUCache(4) => [5, 4, 'A', 3]" diff --git a/requirements.txt b/requirements.txt index e01d87cffabe..9a26dcc21f36 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,5 +16,4 @@ sympy tensorflow texttable tweepy -types-requests xgboost