Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pokedex#16: "adds synchronous local storage" (#17)
- Loading branch information
1 parent
97b701d
commit 4c9dd6f
Showing
15 changed files
with
265 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from typing import Any, Dict | ||
|
||
PokeApiEndpoints = Dict[str, str] | ||
Pokemon = Dict[str, Any] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from pathlib import Path | ||
|
||
PROJECTROOT = Path(__file__).parent.parent.absolute() | ||
DBROOT = PROJECTROOT / "pokedex" / "db" | ||
CACHEPATH = DBROOT / "cache" |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import dbm | ||
import json | ||
from dataclasses import dataclass | ||
from typing import AnyStr, Optional | ||
|
||
from actionpack import Action | ||
|
||
from pokedex.constants import CACHEPATH | ||
from pokedex.db.models import DeferredRequest | ||
|
||
|
||
@dataclass | ||
class DbInsertRequestResult(Action): | ||
key: AnyStr | ||
value: DeferredRequest | ||
db: Optional[str] = None | ||
|
||
def __post_init__(self): | ||
self.set(name=self.key) | ||
|
||
def instruction(self) -> bool: | ||
db = self.db or str(CACHEPATH) | ||
response = self.value() # external call | ||
with dbm.open(db, "c") as cache: | ||
cache[self.key] = json.dumps(response.json()) | ||
return True | ||
|
||
|
||
@dataclass | ||
class DbInsert(Action): | ||
key: AnyStr | ||
value: AnyStr | ||
db: Optional[str] = None | ||
|
||
def instruction(self) -> str: | ||
db = self.db or str(CACHEPATH) | ||
with dbm.open(db, "c") as cache: | ||
cache[self.key] = self.value | ||
return self.key | ||
|
||
|
||
@dataclass | ||
class DbRead(Action[str, bytes]): | ||
key: bytes | ||
db: Optional[str] = None | ||
|
||
def instruction(self) -> bytes: | ||
db = self.db or str(CACHEPATH) | ||
with dbm.open(db, "c") as cache: # create db if not exists | ||
return cache[self.key] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import json | ||
from typing import Iterable | ||
|
||
import requests | ||
from actionpack import KeyedProcedure | ||
|
||
from pokedex.db.actions import DbInsert, DbInsertRequestResult, DbRead | ||
from pokedex.db.models import DeferredRequest | ||
|
||
|
||
def persist_requests(requests: Iterable[DeferredRequest]): | ||
db_inserts = (DbInsertRequestResult(key=rq.url, value=rq) for rq in requests) | ||
procedure = KeyedProcedure[str, dict](db_inserts).execute(should_raise=True) | ||
for key, result in procedure: | ||
yield key, result.value | ||
|
||
|
||
def cached_get(url: str) -> requests.Response: | ||
cache_result = DbRead(url.encode()).perform() | ||
if cache_result.successful: | ||
response = requests.Response() | ||
response._content = cache_result.value | ||
response.status_code = 200 | ||
else: | ||
response = requests.get(url) | ||
response.raise_for_status() # TODO: handle error states | ||
DbInsert(key=url, value=json.dumps(response.json())).perform(should_raise=True) | ||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import json | ||
from dataclasses import asdict, dataclass | ||
from typing import Any, Dict, List, Type, Union | ||
|
||
from requests import Response | ||
from typing_extensions import Protocol | ||
|
||
|
||
class DeferredRequest(Protocol): | ||
url: str | ||
|
||
def __call__(self) -> Response: | ||
pass | ||
|
||
|
||
JSON = Union[Dict[str, Any], List[Any], int, str, float, bool, Type[None]] | ||
|
||
|
||
@dataclass | ||
class Report: | ||
persisted: dict | ||
|
||
def __str__(self) -> JSON: | ||
summary = dict(asdict(self), count=len(self.persisted)) | ||
return json.dumps(summary, indent=4) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
poetry==1.5.1 | ||
typing_extensions==4.6.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from unittest import TestCase | ||
from unittest.mock import patch | ||
|
||
from pokedex.db.actions import DbRead | ||
from tests.fixtures import resource | ||
|
||
|
||
class TestActions(TestCase): | ||
@patch("dbm.open") | ||
def test_can_read_cache(self, mock_kv_open): | ||
key = "https://pokeapi.co/api/v2/pokemon/39/" | ||
pokemon_data = resource("jigglypuff.response") | ||
mock_kv_open.return_value.__enter__.return_value.__getitem__.return_value = pokemon_data | ||
mock_kv_open.assert_not_called() | ||
result = DbRead(key=key).perform(should_raise=True) | ||
mock_kv_open.assert_called_once() | ||
assert result.value == pokemon_data |
Oops, something went wrong.