Skip to content

Commit

Permalink
general: do not export legacy NTBinder, move stuff testing it to lega…
Browse files Browse the repository at this point in the history
…cy and add some more tests
  • Loading branch information
karlicoss committed Oct 2, 2024
1 parent d969672 commit 5c93e28
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 56 deletions.
3 changes: 0 additions & 3 deletions src/cachew/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -848,13 +848,10 @@ def cached_items():
yield from func(*args, **kwargs)


from .legacy import NTBinder

__all__ = [
'cachew',
'CachewException',
'SourceHash',
'HashFunction',
'get_logger',
'NTBinder', # NOTE: we need to keep this here for now because it's used in promnesia
]
17 changes: 17 additions & 0 deletions src/cachew/legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import sqlalchemy
from sqlalchemy import Column

from .pytest import parametrize
from .utils import CachewException


Expand Down Expand Up @@ -470,3 +471,19 @@ def types(ts):

for p in PRIMITIVE_TYPES:
assert p in Values.__args__ # type: ignore


@parametrize(
('tp', 'val'),
[
(int, 22),
(bool, False),
(Optional[str], 'abacaba'),
(Union[str, int], 1),
],
)
def test_ntbinder_primitive(tp, val) -> None:
b = NTBinder.make(tp, name='x')
row = b.to_row(val)
vv = b.from_row(list(row))
assert vv == val
19 changes: 19 additions & 0 deletions src/cachew/pytest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""
Helpers to prevent depending on pytest in runtime
"""
import sys
import typing

under_pytest = 'pytest' in sys.modules

if typing.TYPE_CHECKING or under_pytest:
import pytest

parametrize = pytest.mark.parametrize
else:

def parametrize(*_args, **_kwargs):
def wrapper(f):
return f

return wrapper
2 changes: 1 addition & 1 deletion src/cachew/tests/marshall.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import pytest
import pytz

from ..legacy import NTBinder
from ..marshall.cachew import CachewMarshall
from ..marshall.common import Json
from .utils import (
Expand Down Expand Up @@ -45,6 +44,7 @@ def do_test(*, test_name: str, Type, factory, count: int, impl: Impl = 'cachew')
to_json = marshall.dump
from_json = marshall.load
elif impl == 'legacy':
from ..legacy import NTBinder
# NOTE: legacy binder emits a tuple which can be inserted directly into the database
# so 'json dump' and 'json load' should really be disregarded for this flavor
# if you're comparing with <other> implementation, you should compare
Expand Down
97 changes: 45 additions & 52 deletions src/cachew/tests/test_cachew.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
from .. import (
Backend,
CachewException,
NTBinder,
cachew,
callable_name,
get_logger,
Expand Down Expand Up @@ -80,22 +79,6 @@ def restore_settings():
setattr(settings, k, v)


# fmt: off
@pytest.mark.parametrize(('tp', 'val'), [
(int, 22),
(bool, False),
(Optional[str], 'abacaba'),
(Union[str, int], 1),
])
# fmt: on
def test_ntbinder_primitive(tp, val) -> None:
# TODO good candidate for property tests...
b = NTBinder.make(tp, name='x')
row = b.to_row(val)
vv = b.from_row(list(row))
assert vv == val


class UUU(NamedTuple):
xx: int
yy: int
Expand Down Expand Up @@ -582,12 +565,14 @@ def make_people_data(count: int) -> Iterator[Person]:
)


class Breaky(NamedTuple):
job_title: int
job: Optional[Job]
def test_unique_columns(tmp_path: Path) -> None:
# TODO remove this test? it's for legacy stuff..
from ..legacy import NTBinder

class Breaky(NamedTuple):
job_title: int
job: Optional[Job]

def test_unique(tmp_path: Path) -> None:
assert [c.name for c in NTBinder.make(Breaky).columns] == [
'job_title',
'_job_is_null',
Expand Down Expand Up @@ -698,46 +683,53 @@ def fun() -> Iterable[Dates]:
# fmt: off
@dataclass
class AllTypes:
an_int : int
a_bool : bool
a_float: float
a_str : str
a_dt : datetime
a_date : date
a_json : Dict[str, Any]
a_list : List[Any]
an_exc : Exception
a_str : str
an_int : int
a_float : float
a_bool : bool
a_dt : datetime
a_date : date
a_dict : Dict[str, Any]
a_list : List[Any]
a_tuple : Tuple[float, str]
an_exc : Exception
an_opt : Optional[str]
# fmt: on

# TODO test new style list/tuple/union/optional
# TODO support vararg tuples?


def test_types(tmp_path: Path) -> None:
tz = pytz.timezone('Europe/Berlin')
# fmt: off
obj = AllTypes(
an_int =1123,
a_bool =True,
a_float=3.131,
a_str ='abac',
a_dt =datetime.now(tz=tz),
a_date =datetime.now().replace(year=2000).date(),
a_json ={'a': True, 'x': {'whatever': 3.14}},
a_list =['aba', 123, None],
an_exc =RuntimeError('error!', 123),
a_str = 'abac',
an_int = 1123,
a_float = 3.131,
a_bool = True,
a_dt = datetime.now(tz=tz),
a_date = datetime.now().replace(year=2000).date(),
a_dict = {'a': True, 'x': {'whatever': 3.14}},
a_list = ['aba', 123, None],
a_tuple = (1.23, '3.2.1'),
an_exc = RuntimeError('error!', 123),
an_opt = 'hello',
)
# fmt: on

@cachew(tmp_path)
def get() -> Iterator[AllTypes]:
yield obj

def H(t: AllTypes):
def helper(t: AllTypes):
# Exceptions can't be directly compared.. so this kinda helps
d = asdict(t)
d['an_exc'] = d['an_exc'].args
return d

assert H(one(get())) == H(obj)
assert H(one(get())) == H(obj)
assert helper(one(get())) == helper(obj)
assert helper(one(get())) == helper(obj)


# TODO if I do perf tests, look at this https://docs.sqlalchemy.org/en/13/_modules/examples/performance/large_resultsets.html
Expand Down Expand Up @@ -786,24 +778,25 @@ class O(NamedTuple):
x: int


def test_default_arguments(tmp_path: Path) -> None:
class HackHash:
def __init__(self, x: int) -> None:
self.x = x
class _HackHash:
def __init__(self, x: int) -> None:
self.x = x

def __repr__(self):
return repr(self.x)
def __repr__(self):
return repr(self.x)

hh = HackHash(1)

def test_default_arguments(tmp_path: Path) -> None:
hh = _HackHash(1)

calls = 0

def orig(a: int, param: HackHash = hh) -> Iterator[O]:
def orig(a: int, param: _HackHash = hh) -> Iterator[O]:
yield O(hh.x)
nonlocal calls
calls += 1

def depends_on(a: int, param: HackHash) -> str:
def depends_on(a: int, param: _HackHash) -> str:
# hmm. in principle this should be str according to typing
# on practice though we always convert hash to str, so maybe type should be changed to Any?
return (a, param.x) # type: ignore[return-value]
Expand All @@ -820,7 +813,7 @@ def depends_on(a: int, param: HackHash) -> str:
assert calls == 2

# should be ok with explicitly passing
assert list(fun(123, param=HackHash(2))) == [O(2)]
assert list(fun(123, param=_HackHash(2))) == [O(2)]
assert calls == 2

# we don't have to handle the default param in the default hash key
Expand Down

0 comments on commit 5c93e28

Please sign in to comment.