Skip to content

Commit

Permalink
Refactor public APIs and remove format_return option (#31)
Browse files Browse the repository at this point in the history
* Refactor public APIs and remove format_return option

We have decided to remove the format_return option, and I have
done that in this PR.

While doing that, I have noticed some deviations from the redis
[spec](https://github.com/redis/redis/tree/unstable/src/commands)
regarding the parameter names and some return values. I have updated
some parameter names according to the spec.

Also, there were some inconsistencies (some methods were returing
"OK" for simple string responses while others were returning boolean)
regarding the return types, so I have fixed them as well.

I have also refactored some of the public APIs related to geo
commands. It was cumbersome to use dict as the variadic parameter values
so I converted most of them to simple tuples.

* rename run to execute

* do not export async redis from the __init__.py
  • Loading branch information
mdumandag authored Jul 9, 2023
1 parent bd765a9 commit 7eed1d1
Show file tree
Hide file tree
Showing 100 changed files with 1,456 additions and 2,097 deletions.
12 changes: 3 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ The SDK is currently compatible with python 3.8 and above.
- [Custom commands](#custom-commands)
- [Encoding](#encoding)
- [Retry mechanism](#retry-mechanism)
- [Formatting returns](#formatting-returns)
- [Contributing](#contributing)
- [Preparing the environment](#preparing-the-environment)
- [Running tests](#running-tests)
Expand Down Expand Up @@ -110,11 +109,11 @@ the `BITFIELD` and, respectively, `BITFIELD_RO` classes. Use the `execute` funct
```

### Custom commands
If you want to run a command that hasn't been implemented, you can use the `run` function of your client instance
and pass the command as `list`
If you want to run a command that hasn't been implemented, you can use the `execute` function of your client instance
and pass the command as a `list`.

```python
redis.run(command=["XLEN", "test_stream"])
redis.execute(command=["XLEN", "test_stream"])
```

# Encoding
Expand All @@ -129,11 +128,6 @@ For very large data, this can add a few milliseconds in latency. So, if you're s
upstash-redis has a fallback mechanism in case of network or API issues. By default, if a request fails it'll retry once, 3 seconds
after the error. If you want to customize that, set `rest_retries` and `rest_retry_interval` (in seconds).

# Formatting returns
The SDK relies on the Upstash REST proxy, which returns the `RESP2` responses of the given commands.
By default, we apply formatting to some of them to provide a better developer experience.
If you want the commands to output the raw return, set `format_return` to `False`.

# Contributing

## Preparing the environment
Expand Down
8 changes: 4 additions & 4 deletions tests/commands/asyncio/bitmap/test_bitcount.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
from pytest import mark, raises

from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert await async_redis.bitcount("string") == 17


@mark.asyncio
async def test_with_interval(async_redis: AsyncRedis) -> None:
async def test_with_interval(async_redis: Redis) -> None:
assert await async_redis.bitcount("string", start=1, end=2) == 9


@mark.asyncio
async def test_with_invalid_interval(async_redis: AsyncRedis) -> None:
async def test_with_invalid_interval(async_redis: Redis) -> None:
with raises(Exception) as exception:
await async_redis.bitcount("string", end=2)

Expand Down
12 changes: 6 additions & 6 deletions tests/commands/asyncio/bitmap/test_bitfield.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from pytest import mark

from tests.execute_on_http import execute_on_http
from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test_get(async_redis: AsyncRedis) -> None:
async def test_get(async_redis: Redis) -> None:
# With integer offset.
assert await async_redis.bitfield("string").get(
encoding="u8", offset=0
Expand All @@ -18,7 +18,7 @@ async def test_get(async_redis: AsyncRedis) -> None:


@mark.asyncio
async def test_set(async_redis: AsyncRedis) -> None:
async def test_set(async_redis: Redis) -> None:
# With integer offset.
assert await async_redis.bitfield("string_for_bitfield_set").set(
encoding="u8", offset=0, value=97
Expand All @@ -41,7 +41,7 @@ async def test_set(async_redis: AsyncRedis) -> None:


@mark.asyncio
async def test_incrby(async_redis: AsyncRedis) -> None:
async def test_incrby(async_redis: Redis) -> None:
# With integer offset.
assert await (
async_redis.bitfield("string_for_bitfield_incrby")
Expand All @@ -66,7 +66,7 @@ async def test_incrby(async_redis: AsyncRedis) -> None:


@mark.asyncio
async def test_chained_commands(async_redis: AsyncRedis) -> None:
async def test_chained_commands(async_redis: Redis) -> None:
assert await (
async_redis.bitfield("string_for_bitfield_chained_commands")
.set(encoding="u8", offset=0, value=97)
Expand All @@ -80,7 +80,7 @@ async def test_chained_commands(async_redis: AsyncRedis) -> None:


@mark.asyncio
async def test_overflow(async_redis: AsyncRedis) -> None:
async def test_overflow(async_redis: Redis) -> None:
assert await (
async_redis.bitfield("string_for_bitfield_overflow")
.incrby(encoding="i8", offset=100, increment=100)
Expand Down
6 changes: 3 additions & 3 deletions tests/commands/asyncio/bitmap/test_bitfield_ro.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from pytest import mark

from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test_get(async_redis: AsyncRedis) -> None:
async def test_get(async_redis: Redis) -> None:
# With integer offset.
assert await async_redis.bitfield_ro("string").get(
encoding="u8", offset=0
Expand All @@ -17,7 +17,7 @@ async def test_get(async_redis: AsyncRedis) -> None:


@mark.asyncio
async def test_chained_commands(async_redis: AsyncRedis) -> None:
async def test_chained_commands(async_redis: Redis) -> None:
assert await (
async_redis.bitfield_ro("string")
.get(encoding="u8", offset=0)
Expand Down
10 changes: 5 additions & 5 deletions tests/commands/asyncio/bitmap/test_bitop.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
from pytest import mark, raises

from tests.execute_on_http import execute_on_http
from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test_not_not_operation(async_redis: AsyncRedis) -> None:
async def test_not_not_operation(async_redis: Redis) -> None:
assert (
await async_redis.bitop(
"AND",
Expand All @@ -21,15 +21,15 @@ async def test_not_not_operation(async_redis: AsyncRedis) -> None:


@mark.asyncio
async def test_without_source_keys(async_redis: AsyncRedis) -> None:
async def test_without_source_keys(async_redis: Redis) -> None:
with raises(Exception) as exception:
await async_redis.bitop("AND", "bitop_destination_1")

assert str(exception.value) == "At least one source key must be specified."


@mark.asyncio
async def test_not_with_more_than_one_source_key(async_redis: AsyncRedis) -> None:
async def test_not_with_more_than_one_source_key(async_redis: Redis) -> None:
with raises(Exception) as exception:
await async_redis.bitop(
"NOT",
Expand All @@ -45,7 +45,7 @@ async def test_not_with_more_than_one_source_key(async_redis: AsyncRedis) -> Non


@mark.asyncio
async def test_not(async_redis: AsyncRedis) -> None:
async def test_not(async_redis: Redis) -> None:
assert (
await async_redis.bitop(
"NOT", "bitop_destination_4", "string_as_bitop_source_1"
Expand Down
8 changes: 4 additions & 4 deletions tests/commands/asyncio/bitmap/test_bitpos.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
from pytest import mark, raises

from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert await async_redis.bitpos("string", bit=1) == 1


@mark.asyncio
async def test_with_interval(async_redis: AsyncRedis) -> None:
async def test_with_interval(async_redis: Redis) -> None:
assert await async_redis.bitpos("string", bit=0, start=1, end=0) == -1

assert await async_redis.bitpos("string", bit=0, start=1) == 8


@mark.asyncio
async def test_with_start_and_not_end(async_redis: AsyncRedis) -> None:
async def test_with_start_and_not_end(async_redis: Redis) -> None:
with raises(Exception) as exception:
await async_redis.bitpos("string", bit=0, end=2)

Expand Down
4 changes: 2 additions & 2 deletions tests/commands/asyncio/bitmap/test_getbit.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from pytest import mark

from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert await async_redis.getbit(key="string", offset=1) == 1
4 changes: 2 additions & 2 deletions tests/commands/asyncio/bitmap/test_setbit.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from pytest import mark

from tests.execute_on_http import execute_on_http
from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert await async_redis.setbit("setbit", offset=4, value=1) == 0

assert await execute_on_http("GETBIT", "setbit", "4") == 1
4 changes: 2 additions & 2 deletions tests/commands/asyncio/connection/test_echo.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from pytest import mark

from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert await async_redis.echo(message="Upstash is nice!") == "Upstash is nice!"
6 changes: 3 additions & 3 deletions tests/commands/asyncio/connection/test_ping.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from pytest import mark

from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert await async_redis.ping() == "PONG"


@mark.asyncio
async def test_with_message(async_redis: AsyncRedis) -> None:
async def test_with_message(async_redis: Redis) -> None:
assert await async_redis.ping(message="Upstash is nice!") == "Upstash is nice!"
19 changes: 5 additions & 14 deletions tests/commands/asyncio/generic/test_copy.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from pytest import mark

from tests.execute_on_http import execute_on_http
from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert (
await async_redis.copy(source="string", destination="copy_destination") is True
)
Expand All @@ -14,7 +14,7 @@ async def test(async_redis: AsyncRedis) -> None:


@mark.asyncio
async def test_with_replace(async_redis: AsyncRedis) -> None:
async def test_with_replace(async_redis: Redis) -> None:
assert (
await async_redis.copy(
source="string", destination="string_as_copy_destination", replace=True
Expand All @@ -26,18 +26,9 @@ async def test_with_replace(async_redis: AsyncRedis) -> None:


@mark.asyncio
async def test_without_formatting(async_redis: AsyncRedis) -> None:
async_redis._format_return = False

assert (
await async_redis.copy(source="string", destination="copy_destination_2") == 1
)


@mark.asyncio
async def test_with_formatting(async_redis: AsyncRedis) -> None:
async def test_with_formatting(async_redis: Redis) -> None:
await async_redis.copy(source="string", destination="copy_destination_2")
assert (
await async_redis.copy(source="string", destination="copy_destination_2")
== False
is False
)
6 changes: 3 additions & 3 deletions tests/commands/asyncio/generic/test_delete.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from pytest import mark, raises

from tests.execute_on_http import execute_on_http
from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert await async_redis.delete("string_for_delete_1", "string_for_delete_2") == 2

assert (
Expand All @@ -15,7 +15,7 @@ async def test(async_redis: AsyncRedis) -> None:


@mark.asyncio
async def test_without_keys(async_redis: AsyncRedis) -> None:
async def test_without_keys(async_redis: Redis) -> None:
with raises(Exception) as exception:
await async_redis.delete()

Expand Down
6 changes: 3 additions & 3 deletions tests/commands/asyncio/generic/test_exists.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from pytest import mark, raises

from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert await async_redis.exists("string", "hash") == 2


@mark.asyncio
async def test_without_keys(async_redis: AsyncRedis) -> None:
async def test_without_keys(async_redis: Redis) -> None:
with raises(Exception) as exception:
await async_redis.exists()

Expand Down
11 changes: 2 additions & 9 deletions tests/commands/asyncio/generic/test_expire.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,13 @@
from pytest import mark

from tests.execute_on_http import execute_on_http
from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
assert await async_redis.expire("string_for_expire", seconds=1) is True

# Check if the expiry was correctly set.
await sleep(1)
assert await execute_on_http("EXISTS", "string_for_expire") == 0


@mark.asyncio
async def test_without_formatting(async_redis: AsyncRedis) -> None:
async_redis._format_return = False

assert await async_redis.expire("non_existing_key", seconds=1) == 0
14 changes: 2 additions & 12 deletions tests/commands/asyncio/generic/test_expireat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
from pytest import mark

from tests.execute_on_http import execute_on_http
from upstash_redis import AsyncRedis
from upstash_redis.asyncio import Redis


@mark.asyncio
async def test(async_redis: AsyncRedis) -> None:
async def test(async_redis: Redis) -> None:
# Set the expiry one second from the current time.
assert (
await async_redis.expireat(
Expand All @@ -19,13 +19,3 @@ async def test(async_redis: AsyncRedis) -> None:

await sleep(2)
assert await execute_on_http("EXISTS", "string_for_expireat") == 0


@mark.asyncio
async def test_without_formatting(async_redis: AsyncRedis) -> None:
async_redis._format_return = False

assert (
await async_redis.expireat("non_existing_key", unix_time_seconds=1704067200)
== 0
)
Loading

0 comments on commit 7eed1d1

Please sign in to comment.