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

Supports argument score_cast_func in zrangebyscore() #194

Merged
merged 4 commits into from
Jun 15, 2018

Conversation

fferrara
Copy link
Contributor

@fferrara fferrara commented Jun 8, 2018

Fixes #193 #44

@fferrara fferrara force-pushed the zrangebyscore-new-argument branch from ff3332f to fdff224 Compare June 8, 2018 16:17
@coveralls
Copy link

coveralls commented Jun 8, 2018

Coverage Status

Coverage increased (+0.004%) to 98.467% when pulling aa6ff54 on fferrara:zrangebyscore-new-argument into d69718a on jamesls:master.

Copy link
Collaborator

@bmerry bmerry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach looks fine, would just like another test.

How do you feel about extending this to cover the other functions that take a score_cast_func e.g. zrange? I would prefer to add complete support for a feature rather than only half-supporting it.

fakeredis.py Outdated
@@ -1638,11 +1638,13 @@ def zrangebyscore(self, name, min, max,

``withscores`` indicates to return the scores along with the values.
The return type is a list of (value, score) pairs

`score_cast_func`` a callable used to cast the score return value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing a leading backtick (looks like that's inherited from redis-py, but might as well fix it). Same issue on zrevrangebyscore.

self.redis.zrangebyscore('foo', 2, 3, withscores=True, score_cast_func=round_str),
expected_with_cast_round
)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test looks fine, but can you add a similar test for zrevrangebyscore for completeness.

@fferrara
Copy link
Contributor Author

I'll try to add support for score_cast_func on the other functions. AFAIK they are zscan(), zscan_iter(), zrange(), zrevrange(). Right?

@bmerry
Copy link
Collaborator

bmerry commented Jun 11, 2018

That sounds about right - but I'd suggest just searching for it in redis-py.

@bmerry
Copy link
Collaborator

bmerry commented Jun 11, 2018

Seems like those tests don't pass on real redis. I haven't investigated, but my guess is that redis-py calls the score_cast_func with the raw bytes from the wire, not a float - so you should probably do the same, and then write the tests with a score_cast_func that expects a string (or I'd guess bytes in Python 3).

@fferrara
Copy link
Contributor Author

@bmerry I fixes the tests, they must support strings/bytes indeed. How do you feel about this PR?

@bmerry
Copy link
Collaborator

bmerry commented Jun 12, 2018

It's looking good, but the float/str issue doesn't just affect tests, it needs to be reflected in fakeredis.py too: the float score needs to be encoded as a string before being passed to score_cast_func; and it would be nice if the score_cast_func used in the tests verified that they receive a string (I'd also like to just have one copy of the function, instead of a local copy in each test).

@fferrara
Copy link
Contributor Author

Agreed on the second point.

I'm not sure I follow the first one: "the float score needs to be encoded as a string before being passed to score_cast_func". Actually, as we saw with the tests failing, the score is already a bytes object, not a float. It seems to me that is the responsibility of score_cast_func to know that it will receive a bytes parameter, isn't it?

@bmerry
Copy link
Collaborator

bmerry commented Jun 12, 2018

In redis-py it is a bytes object, but as far as I can see in fakeredis it is still a float. So to emulate redis-py, fakeredis will need to turn the float it has into a bytes object before passing it to score_cast_func (which in the default case will turn it back into a float again).

@@ -74,6 +74,13 @@ def key_val_dict(size=100):
for i in range(size)])


def round_str(x):
if not hasattr(x, 'decode'):
raise AssertionError('Cast argument should be bytes.')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an indirect test - I would just make this a method of the test case, and do self.assertIsInstance(x, bytes).

fakeredis.py Outdated
@@ -1619,16 +1621,17 @@ def zrange(self, name, start, end, desc=False, withscores=False):
if not withscores:
return items
else:
return [(k, all_items[k]) for k in items]
return [(k, score_cast_func(bytes(all_items[k])))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't convert a float to bytes like this in Python 3. Use the to_bytes function instead, which goes via repr.

@fferrara
Copy link
Contributor Author

@bmerry I tried to implement what you intended. Is that right?

@bmerry
Copy link
Collaborator

bmerry commented Jun 14, 2018

There's one very minor tweak I'd like to make in the test, but I'll just merge and make the tweak myself. Thanks for the work on this - it's been a missing feature for quite a while.

@fferrara
Copy link
Contributor Author

Thank you for the support! How long do you think until we have a new tag/version?

@bmerry
Copy link
Collaborator

bmerry commented Jun 15, 2018

I should have time to cut a new version some time in the next week.

When decode_responses is true, the score_cast_func is passed text, not
bytes. To handle this, the score_cast_func handling code was unified in
one helper function which deals with the different cases. It also has a
cut-through path for the default score_cast_func to avoid a lot of
unnecessarily float -> bytes -> text -> float casting.

The unit test is made stricted to check the type exactly.
@bmerry bmerry merged commit a80c02a into jamesls:master Jun 15, 2018
@fferrara
Copy link
Contributor Author

@bmerry can we have a release for that? I'd like to clean up the weird hacks to work around this error

@bmerry
Copy link
Collaborator

bmerry commented Jun 21, 2018

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants