Skip to content

Commit 539da64

Browse files
Python: bitpos valkey8 (#2256)
Python: bitpos valkey8 --------- Signed-off-by: Chloe Yip <chloe.yip@improving.com> Co-authored-by: James Xin <james.xin@improving.com>
1 parent 5dddce2 commit 539da64

File tree

6 files changed

+49
-114
lines changed

6 files changed

+49
-114
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
* Node: Fix BITPOS for Valkey8 ([#2227](https://github.com/valkey-io/valkey-glide/pull/2227))
132132
* Node, Python: Rename `stop` to `end` in sorted set queries ([#2214](https://github.com/valkey-io/valkey-glide/pull/2214))
133133
* Node: Added binary variant to sorted set commands - part 1 ([#2190](https://github.com/valkey-io/valkey-glide/pull/2190))
134+
* Python: Fix BITPOS for Valkey8 ([#2256](https://github.com/valkey-io/valkey-glide/pull/2256))
134135
* Node: Added binary variant to HSCAN command ([#2240](https://github.com/valkey-io/valkey-glide/pull/2240))
135136
* Node: replace decoder by DecoderOption and route by RouteOption in API([#2234](https://github.com/valkey-io/valkey-glide/pull/2234/))
136137
* Node: Added binary variant to sorted set commands ([#2190](https://github.com/valkey-io/valkey-glide/pull/2190), [#2210](https://github.com/valkey-io/valkey-glide/pull/2210))

python/python/glide/async_commands/bitmap.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ def __init__(
3737
3838
Args:
3939
start (int): The starting offset index.
40-
end (int): The ending offset index. Optional since Valkey version 8.0.0 and above. If not provided, it will default to the end of the string.
40+
end (Optional[int]): The ending offset index. Optional since Valkey version 8.0.0 and above for the BITCOUNT
41+
command. If not provided, it will default to the end of the string.
4142
index_type (Optional[BitmapIndexType]): The index offset type. This option can only be specified if you are
4243
using Valkey version 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`.
4344
If no index type is provided, the indexes will be assumed to be byte indexes.
@@ -260,8 +261,8 @@ class BitOverflowControl(Enum):
260261

261262
WRAP = "WRAP"
262263
"""
263-
Performs modulo when overflows occur with unsigned encoding. When overflows occur with signed encoding, the value
264-
restarts at the most negative value. When underflows occur with signed encoding, the value restarts at the most
264+
Performs modulo when overflows occur with unsigned encoding. When overflows occur with signed encoding, the value
265+
restarts at the most negative value. When underflows occur with signed encoding, the value restarts at the most
265266
positive value.
266267
"""
267268
SAT = "SAT"

python/python/glide/async_commands/core.py

Lines changed: 14 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5667,20 +5667,25 @@ async def getbit(self, key: TEncodable, offset: int) -> int:
56675667
)
56685668

56695669
async def bitpos(
5670-
self, key: TEncodable, bit: int, start: Optional[int] = None
5670+
self, key: TEncodable, bit: int, options: Optional[OffsetOptions] = None
56715671
) -> int:
56725672
"""
56735673
Returns the position of the first bit matching the given `bit` value. The optional starting offset
56745674
`start` is a zero-based index, with `0` being the first byte of the list, `1` being the next byte and so on.
56755675
The offset can also be a negative number indicating an offset starting at the end of the list, with `-1` being
56765676
the last byte of the list, `-2` being the penultimate, and so on.
56775677
5678+
If you are using Valkey 7.0.0 or above, the optional `index_type` can also be provided to specify whether the
5679+
`start` and `end` offsets specify BIT or BYTE offsets. If `index_type` is not provided, BYTE offsets
5680+
are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is
5681+
specified, `start=0` and `end=2` means to look at the first three bytes.
5682+
56785683
See https://valkey.io/commands/bitpos for more details.
56795684
56805685
Args:
56815686
key (TEncodable): The key of the string.
56825687
bit (int): The bit value to match. Must be `0` or `1`.
5683-
start (Optional[int]): The starting offset.
5688+
options (Optional[OffsetOptions]): The offset options.
56845689
56855690
Returns:
56865691
int: The position of the first occurrence of `bit` in the binary value of the string held at `key`.
@@ -5690,60 +5695,18 @@ async def bitpos(
56905695
>>> await client.set("key1", "A1") # "A1" has binary value 01000001 00110001
56915696
>>> await client.bitpos("key1", 1)
56925697
1 # The first occurrence of bit value 1 in the string stored at "key1" is at the second position.
5693-
>>> await client.bitpos("key1", 1, -1)
5698+
>>> await client.bitpos("key1", 1, OffsetOptions(-1))
56945699
10 # The first occurrence of bit value 1, starting at the last byte in the string stored at "key1", is at the eleventh position.
5695-
"""
5696-
args = [key, str(bit)] if start is None else [key, str(bit), str(start)]
5697-
return cast(
5698-
int,
5699-
await self._execute_command(RequestType.BitPos, args),
5700-
)
57015700
5702-
async def bitpos_interval(
5703-
self,
5704-
key: TEncodable,
5705-
bit: int,
5706-
start: int,
5707-
end: int,
5708-
index_type: Optional[BitmapIndexType] = None,
5709-
) -> int:
5710-
"""
5711-
Returns the position of the first bit matching the given `bit` value. The offsets are zero-based indexes, with
5712-
`0` being the first element of the list, `1` being the next, and so on. These offsets can also be negative
5713-
numbers indicating offsets starting at the end of the list, with `-1` being the last element of the list, `-2`
5714-
being the penultimate, and so on.
5715-
5716-
If you are using Valkey 7.0.0 or above, the optional `index_type` can also be provided to specify whether the
5717-
`start` and `end` offsets specify BIT or BYTE offsets. If `index_type` is not provided, BYTE offsets
5718-
are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is
5719-
specified, `start=0` and `end=2` means to look at the first three bytes.
5720-
5721-
See https://valkey.io/commands/bitpos for more details.
5722-
5723-
Args:
5724-
key (TEncodable): The key of the string.
5725-
bit (int): The bit value to match. Must be `0` or `1`.
5726-
start (int): The starting offset.
5727-
end (int): The ending offset.
5728-
index_type (Optional[BitmapIndexType]): The index offset type. This option can only be specified if you are
5729-
using Valkey version 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`.
5730-
If no index type is provided, the indexes will be assumed to be byte indexes.
5731-
5732-
Returns:
5733-
int: The position of the first occurrence from the `start` to the `end` offsets of the `bit` in the binary
5734-
value of the string held at `key`.
5735-
5736-
Examples:
5737-
>>> await client.set("key1", "A12") # "A12" has binary value 01000001 00110001 00110010
5738-
>>> await client.bitpos_interval("key1", 1, 1, -1)
5701+
>>> await client.set("key2", "A12") # "A12" has binary value 01000001 00110001 00110010
5702+
>>> await client.bitpos("key2", 1, OffsetOptions(1, -1))
57395703
10 # The first occurrence of bit value 1 in the second byte to the last byte of the string stored at "key1" is at the eleventh position.
5740-
>>> await client.bitpos_interval("key1", 1, 2, 9, BitmapIndexType.BIT)
5704+
>>> await client.bitpos("key2", 1, OffsetOptions(2, 9, BitmapIndexType.BIT))
57415705
7 # The first occurrence of bit value 1 in the third to tenth bits of the string stored at "key1" is at the eighth position.
57425706
"""
5743-
if index_type is not None:
5744-
args = [key, str(bit), str(start), str(end), index_type.value]
5745-
else:
5746-
args = [key, str(bit), str(start), str(end)]
5707+
args: List[TEncodable] = [key, str(bit)]
5708+
if options is not None:
5709+
args.extend(options.to_args())
57475710

57485711
return cast(
57495712
int,

python/python/glide/async_commands/transaction.py

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4087,7 +4087,7 @@ def bitpos(
40874087
self: TTransaction,
40884088
key: TEncodable,
40894089
bit: int,
4090-
start: Optional[int] = None,
4090+
options: Optional[OffsetOptions] = None,
40914091
) -> TTransaction:
40924092
"""
40934093
Returns the position of the first bit matching the given `bit` value. The optional starting offset
@@ -4100,53 +4100,15 @@ def bitpos(
41004100
Args:
41014101
key (TEncodable): The key of the string.
41024102
bit (int): The bit value to match. Must be `0` or `1`.
4103-
start (Optional[int]): The starting offset.
4103+
options (Optional[OffsetOptions]): The offset options.
41044104
41054105
Command response:
41064106
int: The position of the first occurrence of `bit` in the binary value of the string held at `key`.
41074107
If `start` was provided, the search begins at the offset indicated by `start`.
41084108
"""
4109-
args = [key, str(bit)] if start is None else [key, str(bit), str(start)]
4110-
return self.append_command(RequestType.BitPos, args)
4111-
4112-
def bitpos_interval(
4113-
self: TTransaction,
4114-
key: TEncodable,
4115-
bit: int,
4116-
start: int,
4117-
end: int,
4118-
index_type: Optional[BitmapIndexType] = None,
4119-
) -> TTransaction:
4120-
"""
4121-
Returns the position of the first bit matching the given `bit` value. The offsets are zero-based indexes, with
4122-
`0` being the first element of the list, `1` being the next, and so on. These offsets can also be negative
4123-
numbers indicating offsets starting at the end of the list, with `-1` being the last element of the list, `-2`
4124-
being the penultimate, and so on.
4125-
4126-
If you are using Valkey 7.0.0 or above, the optional `index_type` can also be provided to specify whether the
4127-
`start` and `end` offsets specify BIT or BYTE offsets. If `index_type` is not provided, BYTE offsets
4128-
are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is
4129-
specified, `start=0` and `end=2` means to look at the first three bytes.
4130-
4131-
See https://valkey.io/commands/bitpos for more details.
4132-
4133-
Args:
4134-
key (TEncodable): The key of the string.
4135-
bit (int): The bit value to match. Must be `0` or `1`.
4136-
start (int): The starting offset.
4137-
end (int): The ending offset.
4138-
index_type (Optional[BitmapIndexType]): The index offset type. This option can only be specified if you are
4139-
using Valkey version 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`.
4140-
If no index type is provided, the indexes will be assumed to be byte indexes.
4141-
4142-
Command response:
4143-
int: The position of the first occurrence from the `start` to the `end` offsets of the `bit` in the binary
4144-
value of the string held at `key`.
4145-
"""
4146-
if index_type is not None:
4147-
args = [key, str(bit), str(start), str(end), index_type.value]
4148-
else:
4149-
args = [key, str(bit), str(start), str(end)]
4109+
args: List[TEncodable] = [key, str(bit)]
4110+
if options is not None:
4111+
args.extend(options.to_args())
41504112

41514113
return self.append_command(RequestType.BitPos, args)
41524114

python/python/tests/test_async_client.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7253,7 +7253,7 @@ async def test_getbit(self, glide_client: TGlideClient):
72537253

72547254
@pytest.mark.parametrize("cluster_mode", [True, False])
72557255
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
7256-
async def test_bitpos_and_bitpos_interval(self, glide_client: TGlideClient):
7256+
async def test_bitpos(self, glide_client: TGlideClient):
72577257
key = get_random_string(10)
72587258
non_existing_key = get_random_string(10)
72597259
set_key = get_random_string(10)
@@ -7264,58 +7264,66 @@ async def test_bitpos_and_bitpos_interval(self, glide_client: TGlideClient):
72647264
assert await glide_client.set(key, value) == OK
72657265
assert await glide_client.bitpos(key, 0) == 0
72667266
assert await glide_client.bitpos(key, 1) == 2
7267-
assert await glide_client.bitpos(key, 1, 1) == 9
7268-
assert await glide_client.bitpos_interval(key, 0, 3, 5) == 24
7267+
assert await glide_client.bitpos(key, 1, OffsetOptions(1)) == 9
7268+
assert await glide_client.bitpos(key, 0, OffsetOptions(3, 5)) == 24
72697269

72707270
# `BITPOS` returns -1 for non-existing strings
72717271
assert await glide_client.bitpos(non_existing_key, 1) == -1
7272-
assert await glide_client.bitpos_interval(non_existing_key, 1, 3, 5) == -1
7272+
assert await glide_client.bitpos(non_existing_key, 1, OffsetOptions(3, 5)) == -1
72737273

72747274
# invalid argument - bit value must be 0 or 1
72757275
with pytest.raises(RequestError):
72767276
await glide_client.bitpos(key, 2)
72777277
with pytest.raises(RequestError):
7278-
await glide_client.bitpos_interval(key, 2, 3, 5)
7278+
await glide_client.bitpos(key, 2, OffsetOptions(3, 5))
72797279

72807280
# key exists, but it is not a string
72817281
assert await glide_client.sadd(set_key, [value]) == 1
72827282
with pytest.raises(RequestError):
72837283
await glide_client.bitpos(set_key, 1)
72847284
with pytest.raises(RequestError):
7285-
await glide_client.bitpos_interval(set_key, 1, 1, -1)
7285+
await glide_client.bitpos(set_key, 1, OffsetOptions(1, -1))
72867286

72877287
if await check_if_server_version_lt(glide_client, "7.0.0"):
72887288
# error thrown because BIT and BYTE options were implemented after 7.0.0
72897289
with pytest.raises(RequestError):
7290-
await glide_client.bitpos_interval(key, 1, 1, -1, BitmapIndexType.BYTE)
7290+
await glide_client.bitpos(
7291+
key, 1, OffsetOptions(1, -1, BitmapIndexType.BYTE)
7292+
)
72917293
with pytest.raises(RequestError):
7292-
await glide_client.bitpos_interval(key, 1, 1, -1, BitmapIndexType.BIT)
7294+
await glide_client.bitpos(
7295+
key, 1, OffsetOptions(1, -1, BitmapIndexType.BIT)
7296+
)
72937297
else:
72947298
assert (
7295-
await glide_client.bitpos_interval(key, 0, 3, 5, BitmapIndexType.BYTE)
7299+
await glide_client.bitpos(
7300+
key, 0, OffsetOptions(3, 5, BitmapIndexType.BYTE)
7301+
)
72967302
== 24
72977303
)
72987304
assert (
7299-
await glide_client.bitpos_interval(key, 1, 43, -2, BitmapIndexType.BIT)
7305+
await glide_client.bitpos(
7306+
key, 1, OffsetOptions(43, -2, BitmapIndexType.BIT)
7307+
)
73007308
== 47
73017309
)
73027310
assert (
7303-
await glide_client.bitpos_interval(
7304-
non_existing_key, 1, 3, 5, BitmapIndexType.BYTE
7311+
await glide_client.bitpos(
7312+
non_existing_key, 1, OffsetOptions(3, 5, BitmapIndexType.BYTE)
73057313
)
73067314
== -1
73077315
)
73087316
assert (
7309-
await glide_client.bitpos_interval(
7310-
non_existing_key, 1, 3, 5, BitmapIndexType.BIT
7317+
await glide_client.bitpos(
7318+
non_existing_key, 1, OffsetOptions(3, 5, BitmapIndexType.BIT)
73117319
)
73127320
== -1
73137321
)
73147322

73157323
# key exists, but it is not a string
73167324
with pytest.raises(RequestError):
7317-
await glide_client.bitpos_interval(
7318-
set_key, 1, 1, -1, BitmapIndexType.BIT
7325+
await glide_client.bitpos(
7326+
set_key, 1, OffsetOptions(1, -1, BitmapIndexType.BIT)
73197327
)
73207328

73217329
@pytest.mark.parametrize("cluster_mode", [True, False])

python/python/tests/test_transaction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ async def transaction_test(
558558
args.append(OK)
559559
transaction.bitcount(key20, OffsetOptions(5, 30, BitmapIndexType.BIT))
560560
args.append(17)
561-
transaction.bitpos_interval(key20, 1, 44, 50, BitmapIndexType.BIT)
561+
transaction.bitpos(key20, 1, OffsetOptions(44, 50, BitmapIndexType.BIT))
562562
args.append(46)
563563

564564
if not await check_if_server_version_lt(glide_client, "8.0.0"):

0 commit comments

Comments
 (0)