Skip to content

Commit a0dc538

Browse files
committed
Merge branch 'main' into types
2 parents 38d9f6d + 52597d8 commit a0dc538

File tree

12 files changed

+268
-29
lines changed

12 files changed

+268
-29
lines changed

.github/workflows/integration.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
- uses: actions/checkout@v4
5959
- name: Cache docker images
6060
id: custom-cache
61-
uses: actions/cache@v3
61+
uses: actions/cache@v4
6262
with:
6363
path: ./custom-cache/
6464
key: custom-cache
@@ -94,7 +94,7 @@ jobs:
9494

9595
- name: Cache docker images
9696
id: custom-cache
97-
uses: actions/cache@v3
97+
uses: actions/cache@v4
9898
with:
9999
path: ./custom-cache/
100100
fail-on-cache-miss: true
@@ -150,7 +150,7 @@ jobs:
150150

151151
- name: Cache docker images
152152
id: custom-cache
153-
uses: actions/cache@v3
153+
uses: actions/cache@v4
154154
with:
155155
path: ./custom-cache/
156156
fail-on-cache-miss: true

.github/workflows/spellcheck.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
- name: Checkout
99
uses: actions/checkout@v4
1010
- name: Check Spelling
11-
uses: rojopolis/spellcheck-github-actions@0.41.0
11+
uses: rojopolis/spellcheck-github-actions@0.42.0
1212
with:
1313
config_path: .github/spellcheck-settings.yml
1414
task_name: Markdown

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ Here's how to get started with your code contribution:
9696
c. pip install -r dev_requirements.txt
9797
c. pip install -r requirements.txt
9898

99-
4. If you need a development environment, run `invoke devenv`. Note: this relies on docker-compose to build environments, and assumes that you have a version supporting [docker profiles](https://docs.docker.com/compose/profiles/).
99+
4. If you need a development environment, run `invoke devenv`. Note: this relies on docker compose to build environments, and assumes that you have a version supporting [docker profiles](https://docs.docker.com/compose/profiles/).
100100
5. While developing, make sure the tests pass by running `invoke tests`
101101
6. If you like the change and think the project could use it, send a
102102
pull request

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The Python interface to the Valkey key-value store.
99
[![pre-release](https://img.shields.io/github/v/release/valkey-io/valkey-py?include_prereleases&label=latest-prerelease)](https://github.com/valkey-io/valkey-py/releases)
1010
[![codecov](https://codecov.io/gh/valkey-io/valkey-py/branch/main/graph/badge.svg?token=yenl5fzxxr)](https://codecov.io/gh/valkey-io/valkey-py)
1111

12-
[Installation](#installation) | [Usage](#usage) | [Advanced Topics](#advanced-topics) | [Contributing](https://github.com/valkey-io/valkey-py/blob/main/CONTRIBUTING.md)
12+
[Installation](#installation) | [Usage](#usage) | [Documentation](#documentation) | [Advanced Topics](#advanced-topics) | [Contributing](https://github.com/valkey-io/valkey-py/blob/main/CONTRIBUTING.md)
1313

1414
---------------------------------------------
1515

@@ -85,6 +85,10 @@ Alternatively, you might want to look at [Async connections](https://valkey-py.r
8585

8686
There is built-in support for all of the [out-of-the-box Valkey commands](https://valkey.io/commands). They are exposed using the raw Redis command names (`HSET`, `HGETALL`, etc.) except where a word (i.e. del) is reserved by the language. The complete set of commands can be found [here](https://github.com/valkey-io/valkey-py/tree/main/valkey/commands), or [the documentation](https://valkey-py.readthedocs.io/en/latest/commands.html).
8787

88+
## Documentation
89+
90+
Check out the [documentation](https://valkey-py.readthedocs.io/en/latest/index.html)
91+
8892
## Advanced Topics
8993

9094
The [official Valkey command documentation](https://valkey.io/commands)

docker-compose.yml renamed to compose.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
---
22

3-
version: "3.8"
4-
53
services:
64

75
valkey:

docs/clustering.rst

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,7 @@ Pattern subscribe and publish do not currently work properly due to key
197197
slots. If we hash a pattern like fo\* we will receive a keyslot for that
198198
string but there are endless possibilities for channel names based on
199199
this pattern - unknowable in advance. This feature is not disabled but
200-
the commands are not currently recommended for use. See
201-
`valkey-py-cluster
202-
documentation <https://valkey-py-cluster.readthedocs.io/en/stable/pubsub.html>`__
203-
for more.
200+
the commands are not currently recommended for use.
204201
205202
.. code:: python
206203

docs/examples/opentelemetry/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ pip install -r requirements.txt
3030
**Step 4**. Start the services using Docker and make sure Uptrace is running:
3131

3232
```shell
33-
docker-compose up -d
34-
docker-compose logs uptrace
33+
docker compose up -d
34+
docker compose logs uptrace
3535
```
3636

3737
**Step 5**. Run the Valkey client example and follow the link from the CLI to view the trace:

docs/examples/opentelemetry/docker-compose.yml renamed to docs/examples/opentelemetry/compose.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: "3"
2-
31
services:
42
clickhouse:
53
image: clickhouse/clickhouse-server:22.7

tests/test_asyncio/test_commands.py

Lines changed: 243 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2131,7 +2131,7 @@ async def test_hmset(self, r: valkey.asyncio.Valkey[bytes]):
21312131
)
21322132
h = {b"a": b"1", b"b": b"2", b"c": b"3"}
21332133
with pytest.warns(DeprecationWarning, match=warning_message):
2134-
assert await r.hmset("a", h) # type: ignore[arg-type]
2134+
assert await r.hmset("a", h) # type: ignore[arg-type]
21352135
assert await r.hgetall("a") == h
21362136

21372137
async def test_hsetnx(self, r: valkey.asyncio.Valkey[bytes]):
@@ -2489,6 +2489,248 @@ async def test_geopos_no_value(self, r: valkey.asyncio.Valkey[str]):
24892489
async def test_old_geopos_no_value(self, r: valkey.asyncio.Valkey[str]):
24902490
assert await r.geopos("barcelona", "place1", "place2") == []
24912491

2492+
@skip_if_server_version_lt("6.2.0")
2493+
async def test_geosearch(self, r: valkey.Valkey):
2494+
values = (
2495+
(2.1909389952632, 41.433791470673, "place1")
2496+
+ (2.1873744593677, 41.406342043777, b"\x80place2")
2497+
+ (2.583333, 41.316667, "place3")
2498+
)
2499+
await r.geoadd("barcelona", values)
2500+
assert await r.geosearch(
2501+
"barcelona", longitude=2.191, latitude=41.433, radius=1000
2502+
) == [b"place1"]
2503+
assert await r.geosearch(
2504+
"barcelona", longitude=2.187, latitude=41.406, radius=1000
2505+
) == [b"\x80place2"]
2506+
assert await r.geosearch(
2507+
"barcelona", longitude=2.191, latitude=41.433, height=1000, width=1000
2508+
) == [b"place1"]
2509+
assert await r.geosearch(
2510+
"barcelona", member="place3", radius=100, unit="km"
2511+
) == [
2512+
b"\x80place2",
2513+
b"place1",
2514+
b"place3",
2515+
]
2516+
# test count
2517+
assert await r.geosearch(
2518+
"barcelona", member="place3", radius=100, unit="km", count=2
2519+
) == [b"place3", b"\x80place2"]
2520+
search_res = await r.geosearch(
2521+
"barcelona", member="place3", radius=100, unit="km", count=1, any=1
2522+
)
2523+
assert search_res[0] in [b"place1", b"place3", b"\x80place2"]
2524+
2525+
@skip_unless_arch_bits(64)
2526+
@skip_if_server_version_lt("6.2.0")
2527+
async def test_geosearch_member(self, r: valkey.Valkey):
2528+
values = (2.1909389952632, 41.433791470673, "place1") + (
2529+
2.1873744593677,
2530+
41.406342043777,
2531+
b"\x80place2",
2532+
)
2533+
2534+
await r.geoadd("barcelona", values)
2535+
assert await r.geosearch("barcelona", member="place1", radius=10) == [b"place1"]
2536+
2537+
geosearch_place2, geosearch_place1 = await r.geosearch(
2538+
"barcelona",
2539+
member="place1",
2540+
radius=4000,
2541+
withdist=True,
2542+
withcoord=True,
2543+
withhash=True,
2544+
)
2545+
2546+
# All but the coordinates are identical
2547+
assert geosearch_place2[:-1] == [
2548+
b"\x80place2",
2549+
3067.4157,
2550+
3471609625421029,
2551+
]
2552+
assert_geo_is_close(
2553+
geosearch_place2[-1], (2.187376320362091, 41.40634178640635)
2554+
)
2555+
assert geosearch_place1[:-1] == [
2556+
b"place1",
2557+
0.0,
2558+
3471609698139488,
2559+
]
2560+
assert_geo_is_close(
2561+
geosearch_place1[-1], (2.1909382939338684, 41.433790281840835)
2562+
)
2563+
2564+
@skip_if_server_version_lt("6.2.0")
2565+
async def test_geosearch_sort(self, r: valkey.Valkey):
2566+
values = (2.1909389952632, 41.433791470673, "place1") + (
2567+
2.1873744593677,
2568+
41.406342043777,
2569+
"place2",
2570+
)
2571+
await r.geoadd("barcelona", values)
2572+
assert await r.geosearch(
2573+
"barcelona", longitude=2.191, latitude=41.433, radius=3000, sort="ASC"
2574+
) == [b"place1", b"place2"]
2575+
assert await r.geosearch(
2576+
"barcelona", longitude=2.191, latitude=41.433, radius=3000, sort="DESC"
2577+
) == [b"place2", b"place1"]
2578+
2579+
@skip_unless_arch_bits(64)
2580+
@skip_if_server_version_lt("6.2.0")
2581+
@pytest.mark.parametrize(
2582+
"geosearch_kwargs, expected_geosearch_result",
2583+
[
2584+
(
2585+
{"withdist": True, "withcoord": True, "withhash": True},
2586+
[b"place1", 0.0881, 3471609698139488],
2587+
),
2588+
(
2589+
{"withdist": True, "withcoord": True},
2590+
[b"place1", 0.0881],
2591+
),
2592+
(
2593+
{"withhash": True, "withcoord": True},
2594+
[b"place1", 3471609698139488],
2595+
),
2596+
(
2597+
{"withdist": True, "withhash": True},
2598+
[b"place1", 0.0881, 3471609698139488],
2599+
),
2600+
],
2601+
)
2602+
async def test_geosearch_with(
2603+
self,
2604+
r: valkey.Valkey,
2605+
geosearch_kwargs: dict[str, Any],
2606+
expected_geosearch_result: list[Any],
2607+
):
2608+
values = (2.1909389952632, 41.433791470673, "place1") + (
2609+
2.1873744593677,
2610+
41.406342043777,
2611+
"place2",
2612+
)
2613+
await r.geoadd("barcelona", values)
2614+
2615+
# test a bunch of combinations to test the parse response
2616+
# function.
2617+
geosearch_result = await r.geosearch(
2618+
"barcelona",
2619+
longitude=2.191,
2620+
latitude=41.433,
2621+
radius=1,
2622+
unit="km",
2623+
**geosearch_kwargs,
2624+
)
2625+
assert len(geosearch_result) == 1
2626+
if "withcoord" in geosearch_kwargs:
2627+
assert_geo_is_close(
2628+
geosearch_result[0][-1], (2.1909382939338684, 41.433790281840835)
2629+
)
2630+
assert geosearch_result[0][:-1] == expected_geosearch_result
2631+
else:
2632+
assert geosearch_result == [expected_geosearch_result]
2633+
2634+
assert (
2635+
await r.geosearch(
2636+
"barcelona",
2637+
longitude=2,
2638+
latitude=1,
2639+
radius=1,
2640+
unit="km",
2641+
**geosearch_kwargs,
2642+
)
2643+
== []
2644+
)
2645+
2646+
@skip_if_server_version_lt("6.2.0")
2647+
async def test_geosearch_negative(self, r: valkey.Valkey):
2648+
# not specifying member nor longitude and latitude
2649+
with pytest.raises(exceptions.DataError):
2650+
assert await r.geosearch("barcelona")
2651+
# specifying member and longitude and latitude
2652+
with pytest.raises(exceptions.DataError):
2653+
assert await r.geosearch(
2654+
"barcelona", member="Paris", longitude=2, latitude=1
2655+
)
2656+
# specifying one of longitude and latitude
2657+
with pytest.raises(exceptions.DataError):
2658+
assert await r.geosearch("barcelona", longitude=2)
2659+
with pytest.raises(exceptions.DataError):
2660+
assert await r.geosearch("barcelona", latitude=2)
2661+
2662+
# not specifying radius nor width and height
2663+
with pytest.raises(exceptions.DataError):
2664+
assert await r.geosearch("barcelona", member="Paris")
2665+
# specifying radius and width and height
2666+
with pytest.raises(exceptions.DataError):
2667+
assert await r.geosearch(
2668+
"barcelona", member="Paris", radius=3, width=2, height=1
2669+
)
2670+
# specifying one of width and height
2671+
with pytest.raises(exceptions.DataError):
2672+
assert await r.geosearch("barcelona", member="Paris", width=2)
2673+
with pytest.raises(exceptions.DataError):
2674+
assert await r.geosearch("barcelona", member="Paris", height=2)
2675+
2676+
# invalid sort
2677+
with pytest.raises(exceptions.DataError):
2678+
assert await r.geosearch(
2679+
"barcelona", member="Paris", width=2, height=2, sort="wrong"
2680+
)
2681+
2682+
# invalid unit
2683+
with pytest.raises(exceptions.DataError):
2684+
assert await r.geosearch(
2685+
"barcelona", member="Paris", width=2, height=2, unit="miles"
2686+
)
2687+
2688+
# use any without count
2689+
with pytest.raises(exceptions.DataError):
2690+
assert await r.geosearch("barcelona", member="place3", radius=100, any=1)
2691+
2692+
@pytest.mark.onlynoncluster
2693+
@skip_if_server_version_lt("6.2.0")
2694+
async def test_geosearchstore(self, r: valkey.Valkey):
2695+
values = (2.1909389952632, 41.433791470673, "place1") + (
2696+
2.1873744593677,
2697+
41.406342043777,
2698+
"place2",
2699+
)
2700+
2701+
await r.geoadd("barcelona", values)
2702+
await r.geosearchstore(
2703+
"places_barcelona",
2704+
"barcelona",
2705+
longitude=2.191,
2706+
latitude=41.433,
2707+
radius=1000,
2708+
)
2709+
assert await r.zrange("places_barcelona", 0, -1) == [b"place1"]
2710+
2711+
@pytest.mark.onlynoncluster
2712+
@skip_unless_arch_bits(64)
2713+
@skip_if_server_version_lt("6.2.0")
2714+
async def test_geosearchstore_dist(self, r: valkey.Valkey):
2715+
values = (2.1909389952632, 41.433791470673, "place1") + (
2716+
2.1873744593677,
2717+
41.406342043777,
2718+
"place2",
2719+
)
2720+
2721+
await r.geoadd("barcelona", values)
2722+
await r.geosearchstore(
2723+
"places_barcelona",
2724+
"barcelona",
2725+
longitude=2.191,
2726+
latitude=41.433,
2727+
radius=1000,
2728+
storedist=True,
2729+
)
2730+
# instead of save the geo score, the distance is saved.
2731+
score = await r.zscore("places_barcelona", "place1")
2732+
assert math.isclose(score, 88.05060698409301)
2733+
24922734
@skip_if_server_version_lt("3.2.0")
24932735
async def test_georadius(self, r: valkey.asyncio.Valkey[str]):
24942736
values = (2.1909389952632, 41.433791470673, "place1") + (

tests/test_commands.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3623,15 +3623,15 @@ def test_geosearch_member(self, r):
36233623
)
36243624

36253625
# All but the coordinates are identical
3626-
geosearch_place2[:-1] == [
3626+
assert geosearch_place2[:-1] == [
36273627
b"\x80place2",
36283628
3067.4157,
36293629
3471609625421029,
36303630
]
36313631
assert_geo_is_close(
36323632
geosearch_place2[-1], (2.187376320362091, 41.40634178640635)
36333633
)
3634-
geosearch_place1[:-1] == [
3634+
assert geosearch_place1[:-1] == [
36353635
b"place1",
36363636
0.0,
36373637
3471609698139488,

0 commit comments

Comments
 (0)