From ac6a75be1968c0f3e3a599b3e7dc056d3a212b7e Mon Sep 17 00:00:00 2001 From: Mahmoud Harmouch Date: Tue, 9 Aug 2022 17:40:27 +0300 Subject: [PATCH] fixed a potential bug (#337) * fixed a potential bug Signed-off-by: wiseaidev * add unit tests Signed-off-by: wiseaidev * remove unnecessary logic related to six module Signed-off-by: wiseaidev * remove six from dependencies Signed-off-by: wiseaidev * pass "ignore" as a kwarg Signed-off-by: wiseaidev * get rid of try catch and simplify logic Signed-off-by: wiseaidev * rm poetry.lock Signed-off-by: wiseaidev * rm poetry.lock Signed-off-by: wiseaidev * run black Signed-off-by: wiseaidev * fix mypy issue Signed-off-by: wiseaidev * adjust other tests accordingly Signed-off-by: wiseaidev --- aredis_om/model/model.py | 40 +++++++++++----------------------------- pyproject.toml | 1 - tests/test_hash_model.py | 24 ++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index b4f8288..2a1083d 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -1179,15 +1179,11 @@ class RedisModel(BaseModel, abc.ABC, metaclass=ModelMeta): @classmethod def from_redis(cls, res: Any): # TODO: Parsing logic copied from redisearch-py. Evaluate. - import six - from six.moves import xrange - from six.moves import zip as izip - def to_string(s): - if isinstance(s, six.string_types): + if isinstance(s, (str,)): return s - elif isinstance(s, six.binary_type): - return s.decode("utf-8", "ignore") + elif isinstance(s, bytes): + return s.decode(errors="ignore") else: return s # Not a string we care about @@ -1195,34 +1191,20 @@ class RedisModel(BaseModel, abc.ABC, metaclass=ModelMeta): step = 2 # Because the result has content offset = 1 # The first item is the count of total matches. - for i in xrange(1, len(res), step): - fields_offset = offset - + for i in range(1, len(res), step): fields = dict( - dict( - izip( - map(to_string, res[i + fields_offset][::2]), - map(to_string, res[i + fields_offset][1::2]), - ) + zip( + map(to_string, res[i + offset][::2]), + map(to_string, res[i + offset][1::2]), ) ) - - try: - del fields["id"] - except KeyError: - pass - - try: - fields["json"] = fields["$"] - del fields["$"] - except KeyError: - pass - - if "json" in fields: - json_fields = json.loads(fields["json"]) + # $ means a json entry + if fields.get("$"): + json_fields = json.loads(fields.pop("$")) doc = cls(**json_fields) else: doc = cls(**fields) + docs.append(doc) return docs diff --git a/pyproject.toml b/pyproject.toml index 66aedf7..1ca0303 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,6 @@ redis = ">=3.5.3,<5.0.0" aioredis = "^2.0.0" pydantic = "^1.8.2" click = "^8.0.1" -six = "^1.16.0" pptree = "^3.1" types-redis = ">=3.5.9,<5.0.0" types-six = "^1.16.1" diff --git a/tests/test_hash_model.py b/tests/test_hash_model.py index 0a79aa6..77418ba 100644 --- a/tests/test_hash_model.py +++ b/tests/test_hash_model.py @@ -43,6 +43,7 @@ async def m(key_prefix, redis): created_on: datetime.datetime class Member(BaseHashModel): + id: int = Field(index=True) first_name: str = Field(index=True) last_name: str = Field(index=True) email: str = Field(index=True) @@ -64,6 +65,7 @@ async def m(key_prefix, redis): @pytest_asyncio.fixture async def members(m): member1 = m.Member( + id=0, first_name="Andrew", last_name="Brookins", email="a@example.com", @@ -73,6 +75,7 @@ async def members(m): ) member2 = m.Member( + id=1, first_name="Kim", last_name="Brookins", email="k@example.com", @@ -82,6 +85,7 @@ async def members(m): ) member3 = m.Member( + id=2, first_name="Andrew", last_name="Smith", email="as@example.com", @@ -129,6 +133,9 @@ async def test_exact_match_queries(members, m): ).all() assert actual == [member2] + actual = await m.Member.find(m.Member.id == 0).all() + assert actual == [member1] + @py_test_mark_asyncio async def test_full_text_search_queries(members, m): @@ -176,6 +183,7 @@ async def test_tag_queries_boolean_logic(members, m): @py_test_mark_asyncio async def test_tag_queries_punctuation(m): member1 = m.Member( + id=0, first_name="Andrew, the Michael", last_name="St. Brookins-on-Pier", email="a|b@example.com", # NOTE: This string uses the TAG field separator. @@ -186,6 +194,7 @@ async def test_tag_queries_punctuation(m): await member1.save() member2 = m.Member( + id=1, first_name="Bob", last_name="the Villain", email="a|villain@example.com", # NOTE: This string uses the TAG field separator. @@ -337,18 +346,19 @@ def test_validates_required_fields(m): # Raises ValidationError: last_name is required # TODO: Test the error value with pytest.raises(ValidationError): - m.Member(first_name="Andrew", zipcode="97086", join_date=today) + m.Member(id=0, first_name="Andrew", zipcode="97086", join_date=today) def test_validates_field(m): # Raises ValidationError: join_date is not a date # TODO: Test the error value with pytest.raises(ValidationError): - m.Member(first_name="Andrew", last_name="Brookins", join_date="yesterday") + m.Member(id=0, first_name="Andrew", last_name="Brookins", join_date="yesterday") def test_validation_passes(m): member = m.Member( + id=0, first_name="Andrew", last_name="Brookins", email="a@example.com", @@ -362,6 +372,7 @@ def test_validation_passes(m): @py_test_mark_asyncio async def test_retrieve_first(m): member = m.Member( + id=0, first_name="Simon", last_name="Prickett", email="s@example.com", @@ -373,6 +384,7 @@ async def test_retrieve_first(m): await member.save() member2 = m.Member( + id=1, first_name="Another", last_name="Member", email="m@example.com", @@ -384,6 +396,7 @@ async def test_retrieve_first(m): await member2.save() member3 = m.Member( + id=2, first_name="Third", last_name="Member", email="t@example.com", @@ -401,6 +414,7 @@ async def test_retrieve_first(m): @py_test_mark_asyncio async def test_saves_model_and_creates_pk(m): member = m.Member( + id=0, first_name="Andrew", last_name="Brookins", email="a@example.com", @@ -418,6 +432,7 @@ async def test_saves_model_and_creates_pk(m): @py_test_mark_asyncio async def test_all_pks(m): member = m.Member( + id=0, first_name="Simon", last_name="Prickett", email="s@example.com", @@ -429,6 +444,7 @@ async def test_all_pks(m): await member.save() member1 = m.Member( + id=1, first_name="Andrew", last_name="Brookins", email="a@example.com", @@ -449,6 +465,7 @@ async def test_all_pks(m): @py_test_mark_asyncio async def test_delete(m): member = m.Member( + id=0, first_name="Simon", last_name="Prickett", email="s@example.com", @@ -465,6 +482,7 @@ async def test_delete(m): @py_test_mark_asyncio async def test_expire(m): member = m.Member( + id=0, first_name="Expire", last_name="Test", email="e@example.com", @@ -529,6 +547,7 @@ def test_raises_error_with_lists(m): @py_test_mark_asyncio async def test_saves_many(m): member1 = m.Member( + id=0, first_name="Andrew", last_name="Brookins", email="a@example.com", @@ -537,6 +556,7 @@ async def test_saves_many(m): bio="This is the user bio.", ) member2 = m.Member( + id=1, first_name="Kim", last_name="Brookins", email="k@example.com",