Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typed library #27

Merged
merged 14 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ jobs:
runs-on: "ubuntu-latest"

strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: "actions/checkout@v3"
Expand All @@ -37,7 +38,7 @@ jobs:
key: python-${{ matrix.python-version }}-pydeps-${{ hashFiles('**/poetry.lock') }}
- name: "Install Dependencies"
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: "poetry install --no-interaction --no-root"
run: "poetry install --no-interaction --no-root --all-extras"
- name: "Run Lint"
run: "make lint"
- name: "Run Tests"
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ benchmark:

.PHONY: lint
lint:
poetry run mypy --check-untyped-defs --ignore-missing-imports .
poetry run mypy .
trace_bench:
poetry run python -m benchmarks.trace_bench
17 changes: 15 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ classifiers = [
license = "BSD-3-Clause"

[tool.poetry.dependencies]
python = "^3.7"
python = ">=3.8,<4.0"
typing-extensions = "^4.4.0"
theine-core = "^0.4.3"

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.1"
pytest-benchmark = "^4.0.0"
typing-extensions = "^4.4.0"
mypy = "^1.0.0"
mypy = "1.11.1"
django = "^3.2"
pytest-django = "^4.5.2"
pytest-asyncio = "^0.20.3"
Expand All @@ -30,6 +30,19 @@ isort = "^5.5.0"
py-spy = "^0.3.14"
cacheout = "^0.14.1"
bounded-zipf = "^1.0.0"
django-stubs = "^5.0.2"

[tool.mypy]
strict = true
plugins = ["mypy_django_plugin.main", ]
exclude = [
"benchmarks",
"tests"
]

[tool.django-stubs]
django_settings_module = 'theine'
strict_settings = false

[build-system]
requires = ["poetry-core"]
Expand Down
99 changes: 44 additions & 55 deletions tests/adapters/test_django.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@ def cache() -> Iterable[BaseCache]:


class TestTheineCache:
def test_settings(self, cache: BaseCache):
def test_settings(self, cache: BaseCache) -> None:
assert cache._max_entries == 1000
assert cache.default_timeout == 60

def test_unicode_keys(self, cache: BaseCache):
def test_unicode_keys(self, cache: BaseCache) -> None:
cache.set("ключ", "value")
res = cache.get("ключ")
assert res == "value"

def test_save_and_integer(self, cache: BaseCache):
def test_save_and_integer(self, cache: BaseCache) -> None:
cache.set("test_key", 2)
res = cache.get("test_key", "Foo")

assert isinstance(res, int)
assert res == 2

def test_save_string(self, cache: BaseCache):
def test_save_string(self, cache: BaseCache) -> None:
cache.set("test_key", "hello" * 1000)
res = cache.get("test_key")

Expand All @@ -45,14 +45,14 @@ def test_save_string(self, cache: BaseCache):
assert isinstance(res, str)
assert res == "2"

def test_save_unicode(self, cache: BaseCache):
def test_save_unicode(self, cache: BaseCache) -> None:
cache.set("test_key", "heló")
res = cache.get("test_key")

assert isinstance(res, str)
assert res == "heló"

def test_save_dict(self, cache: BaseCache):
def test_save_dict(self, cache: BaseCache) -> None:
now_dt = datetime.datetime.now()
test_dict = {"id": 1, "date": now_dt, "name": "Foo"}

Expand All @@ -64,7 +64,7 @@ def test_save_dict(self, cache: BaseCache):
assert res["name"] == "Foo"
assert res["date"] == now_dt

def test_save_float(self, cache: BaseCache):
def test_save_float(self, cache: BaseCache) -> None:
float_val = 1.345620002

cache.set("test_key", float_val)
Expand All @@ -73,19 +73,19 @@ def test_save_float(self, cache: BaseCache):
assert isinstance(res, float)
assert res == float_val

def test_timeout(self, cache: BaseCache):
def test_timeout(self, cache: BaseCache) -> None:
cache.set("test_key", 222, timeout=3)
time.sleep(4)

res = cache.get("test_key")
assert res is None

def test_timeout_0(self, cache: BaseCache):
def test_timeout_0(self, cache: BaseCache) -> None:
cache.set("test_key", 222, timeout=0)
res = cache.get("test_key")
assert res is None

def test_timeout_parameter_as_positional_argument(self, cache: BaseCache):
def test_timeout_parameter_as_positional_argument(self, cache: BaseCache) -> None:
cache.set("test_key", 222, -1)
res = cache.get("test_key")
assert res is None
Expand All @@ -97,7 +97,7 @@ def test_timeout_parameter_as_positional_argument(self, cache: BaseCache):
assert res1 == 222
assert res2 is None

def test_timeout_negative(self, cache: BaseCache):
def test_timeout_negative(self, cache: BaseCache) -> None:
cache.set("test_key", 222, timeout=-1)
res = cache.get("test_key")
assert res is None
Expand All @@ -107,71 +107,60 @@ def test_timeout_negative(self, cache: BaseCache):
res = cache.get("test_key")
assert res is None

def test_timeout_tiny(self, cache: BaseCache):
def test_timeout_tiny(self, cache: BaseCache) -> None:
cache.set("test_key", 222, timeout=0.00001)
res = cache.get("test_key")
assert res in (None, 222)

def test_set_add(self, cache: BaseCache):
def test_set_add(self, cache: BaseCache) -> None:
cache.set("add_key", "Initial value")
res = cache.add("add_key", "New value")
assert res is False
assert cache.add("add_key", "New value") is False

res = cache.get("add_key")
assert res == "Initial value"
res = cache.add("other_key", "New value")
assert res is True
assert cache.get("add_key") == "Initial value"
assert cache.add("other_key", "New value") is True

def test_get_many(self, cache: BaseCache):
def test_get_many(self, cache: BaseCache) -> None:
cache.set("a", 1)
cache.set("b", 2)
cache.set("c", 3)

res = cache.get_many(["a", "b", "c"])
assert res == {"a": 1, "b": 2, "c": 3}

def test_get_many_unicode(self, cache: BaseCache):
def test_get_many_unicode(self, cache: BaseCache) -> None:
cache.set("a", "1")
cache.set("b", "2")
cache.set("c", "3")

res = cache.get_many(["a", "b", "c"])
assert res == {"a": "1", "b": "2", "c": "3"}

def test_set_many(self, cache: BaseCache):
def test_set_many(self, cache: BaseCache) -> None:
cache.set_many({"a": 1, "b": 2, "c": 3})
res = cache.get_many(["a", "b", "c"])
assert res == {"a": 1, "b": 2, "c": 3}

def test_delete(self, cache: BaseCache):
def test_delete(self, cache: BaseCache) -> None:
cache.set_many({"a": 1, "b": 2, "c": 3})
res = cache.delete("a")
assert bool(res) is True

res = cache.get_many(["a", "b", "c"])
assert res == {"b": 2, "c": 3}
assert cache.delete("a") is True
assert cache.get_many(["a", "b", "c"]) == {"b": 2, "c": 3}
assert cache.delete("a") is False

res = cache.delete("a")
assert bool(res) is False

def test_delete_many(self, cache: BaseCache):
def test_delete_many(self, cache: BaseCache) -> None:
cache.set_many({"a": 1, "b": 2, "c": 3})
res = cache.delete_many(["a", "b"])
res = cache.get_many(["a", "b", "c"])
assert res == {"c": 3}
cache.delete_many(["a", "b"])
assert cache.get_many(["a", "b", "c"]) == {"c": 3}

def test_delete_many_generator(self, cache: BaseCache):
def test_delete_many_generator(self, cache: BaseCache) -> None:
cache.set_many({"a": 1, "b": 2, "c": 3})
res = cache.delete_many(key for key in ["a", "b"])
cache.delete_many(key for key in ["a", "b"])
res = cache.get_many(["a", "b", "c"])
assert res == {"c": 3}

def test_delete_many_empty_generator(self, cache: BaseCache):
res = cache.delete_many(key for key in cast(List[str], []))
assert bool(res) is False

def test_incr(self, cache: BaseCache):
def test_delete_many_empty_generator(self, cache: BaseCache) -> None:
cache.delete_many(key for key in cast(List[str], []))

def test_incr(self, cache: BaseCache) -> None:
cache.set("num", 1)
cache.incr("num")
res = cache.get("num")
Expand All @@ -198,7 +187,7 @@ def test_incr(self, cache: BaseCache):
res = cache.get("num")
assert res == 5

def test_incr_no_timeout(self, cache: BaseCache):
def test_incr_no_timeout(self, cache: BaseCache) -> None:
cache.set("num", 1, timeout=None)

cache.incr("num")
Expand Down Expand Up @@ -226,7 +215,7 @@ def test_incr_no_timeout(self, cache: BaseCache):
res = cache.get("num")
assert res == 5

def test_get_set_bool(self, cache: BaseCache):
def test_get_set_bool(self, cache: BaseCache) -> None:
cache.set("bool", True)
res = cache.get("bool")

Expand All @@ -239,15 +228,15 @@ def test_get_set_bool(self, cache: BaseCache):
assert isinstance(res, bool)
assert res is False

def test_version(self, cache: BaseCache):
def test_version(self, cache: BaseCache) -> None:
cache.set("keytest", 2, version=2)
res = cache.get("keytest")
assert res is None

res = cache.get("keytest", version=2)
assert res == 2

def test_incr_version(self, cache: BaseCache):
def test_incr_version(self, cache: BaseCache) -> None:
cache.set("keytest", 2)
cache.incr_version("keytest")

Expand All @@ -257,7 +246,7 @@ def test_incr_version(self, cache: BaseCache):
res = cache.get("keytest", version=2)
assert res == 2

def test_ttl_incr_version_no_timeout(self, cache: BaseCache):
def test_ttl_incr_version_no_timeout(self, cache: BaseCache) -> None:
cache.set("my_key", "hello world!", timeout=None)

cache.incr_version("my_key")
Expand All @@ -266,50 +255,50 @@ def test_ttl_incr_version_no_timeout(self, cache: BaseCache):

assert my_value == "hello world!"

def test_touch_zero_timeout(self, cache: BaseCache):
def test_touch_zero_timeout(self, cache: BaseCache) -> None:
cache.set("test_key", 222, timeout=10)

assert cache.touch("test_key", 0) is True
res = cache.get("test_key")
assert res is None

def test_touch_positive_timeout(self, cache: BaseCache):
def test_touch_positive_timeout(self, cache: BaseCache) -> None:
cache.set("test_key", 222, timeout=10)

assert cache.touch("test_key", 2) is True
assert cache.get("test_key") == 222
time.sleep(3)
assert cache.get("test_key") is None

def test_touch_negative_timeout(self, cache: BaseCache):
def test_touch_negative_timeout(self, cache: BaseCache) -> None:
cache.set("test_key", 222, timeout=10)

assert cache.touch("test_key", -1) is True
res = cache.get("test_key")
assert res is None

def test_touch_missed_key(self, cache: BaseCache):
def test_touch_missed_key(self, cache: BaseCache) -> None:
assert cache.touch("test_key_does_not_exist", 1) is False

def test_touch_forever(self, cache: Theine):
def test_touch_forever(self, cache: Theine) -> None:
cache.set("test_key", "foo", timeout=1)
result = cache.touch("test_key", None)
assert result is True
time.sleep(2)
assert cache.get("test_key") == "foo"

def test_touch_forever_nonexistent(self, cache: BaseCache):
def test_touch_forever_nonexistent(self, cache: BaseCache) -> None:
result = cache.touch("test_key_does_not_exist", None)
assert result is False

def test_touch_default_timeout(self, cache: BaseCache):
def test_touch_default_timeout(self, cache: BaseCache) -> None:
cache.set("test_key", "foo", timeout=1)
result = cache.touch("test_key")
assert result is True
time.sleep(2)
assert cache.get("test_key") == "foo"

def test_clear(self, cache: BaseCache):
def test_clear(self, cache: BaseCache) -> None:
cache.set("foo", "bar")
value_from_cache = cache.get("foo")
assert value_from_cache == "bar"
Expand Down
Loading
Loading