1
0
Fork 0

Merging upstream version 1.12.1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 17:10:00 +01:00
parent efb6cb056d
commit 66b78e69ac
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
17 changed files with 293 additions and 71 deletions

View file

@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.12.0
current_version = 1.12.1
commit = True
tag = True

View file

@ -13,7 +13,7 @@ jobs:
matrix:
os: [ubuntu-latest]
python: ['3.6', '3.7', '3.8', '3.9', '3.10']
redis: [5, 6]
redis: [5, 6, 7]
runs-on: ${{ matrix.os }}
services:

View file

@ -1,3 +1,11 @@
## UPCOMING
- Feature: support new command: `HRANDFIELD`.
- Bugfix: all tests pass on redis:7 now.
- Feature: IRedis now accept `username` for auth, redis server version under 6
will ignore `username`.
- Feature: IRedis support prompt now, you can customize prompt string. (thanks to [aymericbeaumet])
## 1.12
- Feature: `CLIENT KILL` now support `LADDR` argument.
@ -15,14 +23,17 @@
- Feature: support new command: `GETEX`.
- Feature: `FLUSHDB` and `FLUSHALL` supports `SYNC` option.
- Feature: `GEOADD` supports `CH XX NX` options.
- Feature: Timestamp Completers are now support completion for timestamp fields and milliseconds timestamp fields.
- Deprecate: `GEORADIUS` is deprecated, no auto-complete for this command anymore.
- Deprecate: `GEORADIUSBYMEMBER` is deprecated, no auto-complete for this command anymore.
- Feature: Timestamp Completers are now support completion for timestamp fields
and milliseconds timestamp fields.
- Deprecate: `GEORADIUS` is deprecated, no auto-complete for this command
anymore.
- Deprecate: `GEORADIUSBYMEMBER` is deprecated, no auto-complete for this
command anymore.
### 1.11.1
- Bugfix: Switch `distutils.version` to `packaging.version` to fix the version parse
for windows. (new dependency: pypi's python-packaging.
- Bugfix: Switch `distutils.version` to `packaging.version` to fix the version
parse for windows. (new dependency: pypi's python-packaging.
## 1.11
@ -282,3 +293,4 @@
[hanaasagi]: https://github.com/Hanaasagi
[sid-maddy]: https://github.com/sid-maddy
[tssujt]: https://github.com/tssujt
[aymericbeaumet]: https://github.com/aymericbeaumet

View file

@ -60,6 +60,8 @@ like `KEYS *` (see
- Written in pure Python, but IRedis was packaged into a single binary with
[PyOxidizer](https://github.com/indygreg/PyOxidizer), you can use cURL to
download and run, it just works, even you don't have a Python interpreter.
- You can change the cli prompt using `--prompt` option or set via `~/.iredisrc`
config file.
- Hide password for `AUTH` command.
- Says "Goodbye!" to you when you exit!
- For full features, please see: [iredis.io](https://www.iredis.io)
@ -190,6 +192,29 @@ staging=redis://username:password@staging-redis.example.com:6379/1
Put this in your `iredisrc` then connect via `iredis -d staging` or
`iredis -d dev`.
### Change The Default Prompt
You can change the prompt str, the default prompt is:
```shell
127.0.0.1:6379>
```
Which is rendered by `{host}:{port}[{db}]> `, you can change this via `--prompt`
option or change
[iredisrc](https://github.com/laixintao/iredis/blob/master/iredis/data/iredisrc)
config file. The prompwt string uses python string format engine, supported
interpolations:
- `{client_name}`
- `{db}`
- `{host}`
- `{path}`
- `{port}`
- `{username}`
- `{client_addr}`
- `{client_id}`
### Configuration
IRedis supports config files. Command-line options will always take precedence

View file

@ -1 +1 @@
__version__ = "1.12.0"
__version__ = "1.12.1"

View file

@ -55,25 +55,35 @@ class Client:
def __init__(
self,
host=None,
port=None,
host="127.0.0.1",
port=6379,
db=0,
password=None,
path=None,
scheme="redis",
username=None,
client_name=None,
prompt=None,
):
self.host = host
self.port = port
self.db = db
self.path = path
# FIXME username is not using...
self.username = username
self.client_name = client_name
self.scheme = scheme
self.password = password
# cli args --prompt will overwrite the prompt in iredisrc config file
self.prompt = ""
if config.prompt:
self.prompt = config.prompt
if prompt:
self.prompt = prompt
self.client_id = None
self.client_addr = None
self.build_connection()
# all command upper case
@ -93,6 +103,13 @@ class Client:
else:
config.no_version_reason = "--no-info flag activated"
if self.prompt and "client_addr" in self.prompt:
self.client_addr = ":".join(
str(x) for x in self.connection._sock.getsockname()
)
if self.prompt and "client_id" in self.prompt:
self.client_id = str(self.execute("CLIENT ID"))
if config.version and re.match(r"([\d\.]+)", config.version):
self.auth_compat(config.version)
@ -131,6 +148,11 @@ class Client:
"socket_keepalive": config.socket_keepalive,
"client_name": client_name,
}
# if username is set without setting paswword, password will be ignored
if password:
connection_kwargs["username"] = username
if scheme == "rediss":
connection_class = SSLConnection
else:
@ -141,6 +163,7 @@ class Client:
"password": password,
"path": path,
"client_name": client_name,
"username": username,
}
connection_class = UnixDomainSocketConnection
@ -150,7 +173,8 @@ class Client:
connection_kwargs["encoding_errors"] = "replace"
logger.debug(
f"connection_class={connection_class}, connection_kwargs={connection_kwargs}"
f"connection_class={connection_class},"
f" connection_kwargs={connection_kwargs}"
)
return connection_class(**connection_kwargs)
@ -191,6 +215,18 @@ class Client:
config.version = version
def __str__(self):
if self.prompt: # not None and not empty
return self.prompt.format(
client_name=self.client_name,
db=self.db,
host=self.host,
path=self.path,
port=self.port,
username=self.username,
client_addr=self.client_addr,
client_id=self.client_id,
)
if self.scheme == "unix":
prompt = f"redis {self.path}"
else:
@ -198,7 +234,8 @@ class Client:
if self.db:
prompt = f"{prompt}[{self.db}]"
return prompt
return f"{prompt}> "
def client_execute_command(self, command_name, *args):
command = command_name.upper()
@ -222,7 +259,8 @@ class Client:
Here we retry once for ConnectionError.
"""
logger.info(
f"execute by connection: connection={connection}, name={command_name}, {args}, {options}"
f"execute by connection: connection={connection}, name={command_name},"
f" {args}, {options}"
)
retry_times = config.retry_times # FIXME configurable
last_error = None
@ -248,7 +286,7 @@ class Client:
last_error = e
retry_times -= 1
need_refresh_connection = True
except (ResponseError) as e:
except ResponseError as e:
response_message = str(e)
if response_message.startswith("MOVED"):
return self.reissue_with_redirect(

View file

@ -63,6 +63,8 @@ class Config:
self.withscores = False
self.version = "Unknown"
self.prompt = None
def __setter__(self, name, value):
# for every time start a transaction
# clear the queued commands first
@ -126,5 +128,6 @@ def load_config_files(iredisrc):
config.shell = config_obj["main"].as_bool("shell")
config.pager = config_obj["main"].get("pager")
config.enable_pager = config_obj["main"].as_bool("enable_pager")
config.prompt = config_obj["main"].get("prompt")
return config_obj

View file

@ -87,6 +87,7 @@ hash,HKEYS,command_key,command_hkeys
hash,HLEN,command_key,render_int
hash,HMGET,command_key_fields,render_list
hash,HMSET,command_key_fieldvalues,render_bulk_string
hash,HRANDFIELD,command_key_count_withvalues,render_list_or_string
hash,HSCAN,command_key_cursor_match_pattern_count,command_hscan
hash,HSET,command_key_field_value,render_int
hash,HSETNX,command_key_field_value,render_int
@ -103,14 +104,14 @@ list,LINDEX,command_key_position,render_bulk_string
list,LINSERT,command_key_positionchoice_pivot_value,render_int
list,LLEN,command_key,render_int
list,LPOS,command_lpos,render_list_or_string
list,LPOP,command_key,render_bulk_string
list,LPOP,command_key,render_list_or_string
list,LPUSH,command_key_values,render_int
list,LPUSHX,command_key_values,render_int
list,LRANGE,command_key_start_end,render_list
list,LREM,command_key_position_value,render_int
list,LSET,command_key_position_value,render_simple_string
list,LTRIM,command_key_start_end,render_simple_string
list,RPOP,command_key,render_bulk_string
list,RPOP,command_key,render_list_or_string
list,RPOPLPUSH,command_key_newkey,render_bulk_string
list,RPUSH,command_key_values,render_int
list,RPUSHX,command_key_value,render_int

1 Group Command Syntax Callback
87 hash HLEN command_key render_int
88 hash HMGET command_key_fields render_list
89 hash HMSET command_key_fieldvalues render_bulk_string
90 hash HRANDFIELD command_key_count_withvalues render_list_or_string
91 hash HSCAN command_key_cursor_match_pattern_count command_hscan
92 hash HSET command_key_field_value render_int
93 hash HSETNX command_key_field_value render_int
104 list LINSERT command_key_positionchoice_pivot_value render_int
105 list LLEN command_key render_int
106 list LPOS command_lpos render_list_or_string
107 list LPOP command_key render_bulk_string render_list_or_string
108 list LPUSH command_key_values render_int
109 list LPUSHX command_key_values render_int
110 list LRANGE command_key_start_end render_list
111 list LREM command_key_position_value render_int
112 list LSET command_key_position_value render_simple_string
113 list LTRIM command_key_start_end render_simple_string
114 list RPOP command_key render_bulk_string render_list_or_string
115 list RPOPLPUSH command_key_newkey render_bulk_string
116 list RPUSH command_key_values render_int
117 list RPUSHX command_key_value render_int

View file

@ -58,6 +58,21 @@ warning = True
# eg. ~/.iredis.log
log_location =
# You can change the prompt str, if left blank, the default prompt would be:
# 127.0.0.1:6379>
# which is rendered by "{host}:{port}[{db}]> "
# supported interpolations:
# {client_name}
# {db}
# {host}
# {path}
# {port}
# {username}
# {client_addr}
# {client_id}
# The prompt string uses python string format engine
prompt =
# History file location
history_location = ~/.iredis_history

View file

@ -123,22 +123,22 @@ def write_result(text, max_height=None):
class Rainbow:
color = [
("#cc2244"),
("#bb4444"),
("#996644"),
("#cc8844"),
("#ccaa44"),
("#bbaa44"),
("#99aa44"),
("#778844"),
("#55aa44"),
("#33aa44"),
("#11aa44"),
("#11aa66"),
("#11aa88"),
("#11aaaa"),
("#11aacc"),
("#11aaee"),
"#cc2244",
"#bb4444",
"#996644",
"#cc8844",
"#ccaa44",
"#bbaa44",
"#99aa44",
"#778844",
"#55aa44",
"#33aa44",
"#11aa44",
"#11aa66",
"#11aa88",
"#11aaaa",
"#11aacc",
"#11aaee",
]
def __init__(self):
@ -160,8 +160,7 @@ class Rainbow:
def prompt_message(client):
# TODO custom prompt
text = "{hostname}> ".format(hostname=str(client))
text = str(client)
if config.rainbow:
return list(zip(Rainbow(), text))
return text
@ -248,8 +247,11 @@ PAGER_HELP = """Using pager when output is too tall for your window, default to
@click.option(
"-s", "--socket", default=None, help="Server socket (overrides hostname and port)."
)
@click.option("-n", help="Database number.(overwrites dsn/url's db number)", default=0)
@click.option(
"-n", help="Database number.(overwrites dsn/url's db number)", default=None
"-u",
"--username",
help="User name used to auth, will be ignore for redis version < 6.",
)
@click.option("-a", "--password", help="Password to use when connecting to the server.")
@click.option("--url", default=None, envvar="IREDIS_URL", help=URL_HELP)
@ -271,6 +273,14 @@ PAGER_HELP = """Using pager when output is too tall for your window, default to
@click.option("--rainbow/--no-rainbow", default=None, is_flag=True, help=RAINBOW)
@click.option("--shell/--no-shell", default=None, is_flag=True, help=SHELL)
@click.option("--pager/--no-pager", default=None, is_flag=True, help=PAGER_HELP)
@click.option(
"--prompt",
default=None,
help=(
"Prompt format (supported interpolations: {client_name}, {db}, {host}, {path},"
" {port}, {username}, {client_addr}, {client_id})."
),
)
@click.version_option()
@click.argument("cmd", nargs=-1)
def gather_args(
@ -278,6 +288,7 @@ def gather_args(
h,
p,
n,
username,
password,
client_name,
newbie,
@ -291,6 +302,7 @@ def gather_args(
socket,
shell,
pager,
prompt,
):
"""
IRedis: Interactive Redis
@ -311,9 +323,9 @@ def gather_args(
load_config_files(iredisrc)
setup_log()
logger.info(
f"[commandline args] host={h}, port={p}, db={n}, newbie={newbie}, "
f"iredisrc={iredisrc}, decode={decode}, raw={raw}, "
f"cmd={cmd}, rainbow={rainbow}."
f"[commandline args] host={h}, port={p}, db={n}, user={username},"
f" newbie={newbie}, iredisrc={iredisrc}, decode={decode}, raw={raw}, cmd={cmd},"
f" rainbow={rainbow}."
)
# raw config
if raw is not None:
@ -368,8 +380,10 @@ def create_client(params):
host = params["h"]
port = params["p"]
db = params["n"]
username = params["username"]
password = params["password"]
client_name = params["client_name"]
prompt = params["prompt"]
dsn_from_url = None
dsn = params["dsn"]
@ -390,17 +404,26 @@ def create_client(params):
scheme=dsn_from_url.scheme,
username=dsn_from_url.username,
client_name=client_name,
prompt=prompt,
)
if params["socket"]:
return Client(
scheme="unix",
path=params["socket"],
db=db,
username=username,
password=password,
client_name=client_name,
prompt=prompt,
)
return Client(
host=host, port=port, db=db, password=password, client_name=client_name
host=host,
port=port,
db=db,
username=username,
password=password,
client_name=client_name,
prompt=prompt,
)

View file

@ -16,6 +16,7 @@ logger = logging.getLogger(__name__)
CONST = {
"failoverchoice": "TAKEOVER FORCE",
"withscores": "WITHSCORES",
"withvalues_const": "WITHVALUES",
"limit": "LIMIT",
"expiration": "EX PX",
"exat_const": "EXAT",
@ -362,6 +363,7 @@ TIMEOUT_CONST = rf"(?P<timeout_const>{c('timeout_const')})"
ABORT_CONST = rf"(?P<abort_const>{c('abort_const')})"
PXAT_CONST = rf"(?P<pxat_const>{c('pxat_const')})"
EXAT_CONST = rf"(?P<exat_const>{c('exat_const')})"
WITHVALUES_CONST = rf"(?P<withvalues_const>{c('withvalues_const')})"
command_grammar = compile(COMMAND)
@ -660,6 +662,10 @@ GRAMMAR = {
(\s+ {EXAT_CONST} \s+ {TIMESTAMP})
)?
\s*""",
"command_key_count_withvalues": rf"""
\s+ {KEY}
(\s+ {COUNT} (\s+ {WITHVALUES_CONST})?)?
\s*""",
}
pipeline = r"(?P<shellcommand>\|.*)?"

20
poetry.lock generated
View file

@ -30,7 +30,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "colorama"
version = "0.4.4"
version = "0.4.5"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
@ -89,7 +89,7 @@ python-versions = "*"
[[package]]
name = "mistune"
version = "2.0.2"
version = "2.0.3"
description = "A sane Markdown parser with useful plugins and renderers"
category = "main"
optional = false
@ -173,11 +173,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "pygments"
version = "2.11.2"
version = "2.12.0"
description = "Pygments is a syntax highlighting package written in Python."
category = "main"
optional = false
python-versions = ">=3.5"
python-versions = ">=3.6"
[[package]]
name = "pyparsing"
@ -305,8 +305,8 @@ click = [
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
]
colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
]
configobj = [
{file = "configobj-5.0.6.tar.gz", hash = "sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902"},
@ -324,8 +324,8 @@ iniconfig = [
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
mistune = [
{file = "mistune-2.0.2-py2.py3-none-any.whl", hash = "sha256:6bab6c6abd711c4604206c7d8cad5cd48b28f072b4bb75797d74146ba393a049"},
{file = "mistune-2.0.2.tar.gz", hash = "sha256:6fc88c3cb49dba8b16687b41725e661cf85784c12e8974a29b9d336dd596c3a1"},
{file = "mistune-2.0.3-py2.py3-none-any.whl", hash = "sha256:e3964140c0775535fba50bd616fe180920044a64bc21850253267b07bff89924"},
{file = "mistune-2.0.3.tar.gz", hash = "sha256:d7605b46b6156b53b7d52a465202b29a6f00f4ea4130ad5d25e9d5547d6b7e50"},
]
packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
@ -375,8 +375,8 @@ py = [
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
]
pygments = [
{file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"},
{file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"},
{file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"},
{file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"},
]
pyparsing = [
{file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "iredis"
version = "1.12.0"
version = "1.12.1"
description = "Terminal client for Redis with auto-completion and syntax highlighting."
authors = ["laixintao <laixintao1995@163.com>"]
readme = 'README.md'

View file

@ -81,3 +81,11 @@ def test_connect_via_socket(fake_redis_socket):
c.expect("redis /tmp/test.sock")
c.close()
def test_iredis_start_with_prompt():
cli = pexpect.spawn("iredis --prompt '{host}abc{port}def{client_name}'", timeout=2)
cli.logfile_read = open("cli_test.log", "ab")
cli.expect("iredis")
cli.expect("127.0.0.1abc6379defNone")
cli.close()

View file

@ -23,3 +23,37 @@ def test_log_location_config():
content = logfile.read()
assert len(content) > 100
def test_load_prompt_from_config(iredis_client, clean_redis):
config_content = dedent(
"""
[main]
prompt = {host}abc{port}xx{db}
"""
)
with open("/tmp/iredisrc", "w+") as etc_config:
etc_config.write(config_content)
cli = pexpect.spawn("iredis -n 15 --iredisrc /tmp/iredisrc", timeout=1)
cli.expect("iredis")
cli.expect("127.0.0.1abc6379xx15")
cli.close()
def test_prompt_cli_overwrite_config(iredis_client, clean_redis):
config_content = dedent(
"""
[main]
prompt = {host}abc{port}xx{db}
"""
)
with open("/tmp/iredisrc", "w+") as etc_config:
etc_config.write(config_content)
cli = pexpect.spawn(
"iredis -n 15 --iredisrc /tmp/iredisrc --prompt='{db}-12345'", timeout=1
)
cli.expect("iredis")
cli.expect("15-12345")
cli.close()

View file

@ -43,3 +43,24 @@ def test_hset(judge_command):
"HSET foo bar hello",
{"command": "HSET", "key": "foo", "field": "bar", "value": "hello"},
)
def test_hrandfield(judge_command):
judge_command(
"HRANDFIELD coin",
{"command": "HRANDFIELD", "key": "coin"},
)
judge_command(
"HRANDFIELD coin -5 WITHVALUES",
{
"command": "HRANDFIELD",
"key": "coin",
"count": "-5",
"withvalues_const": "WITHVALUES",
},
)
judge_command(
"HRANDFIELD coin -5",
{"command": "HRANDFIELD", "key": "coin", "count": "-5"},
)
judge_command("HRANDFIELD coin WITHVALUES", None)

View file

@ -1,3 +1,4 @@
import os
import re
import pytest
import redis
@ -20,6 +21,11 @@ def completer():
return IRedisCompleter()
zset_type = "ziplist"
if os.environ["REDIS_VERSION"] == "7":
zset_type = "listpack"
@pytest.mark.parametrize(
"_input, command_name, expect_args",
[
@ -169,7 +175,16 @@ def test_not_retry_on_authentication_error(iredis_client, config):
iredis_client.execute("None", "GET", ["foo"])
@pytest.mark.skipif("int(os.environ['REDIS_VERSION']) < 6")
@pytest.mark.skipif(
"int(os.environ['REDIS_VERSION']) != 6",
reason="""
in redis7, it will not work if you:
1. connect redis without password
2. set a password
3. auth
the auth will fail""",
)
def test_auto_select_db_and_auth_for_reconnect_only_6(iredis_client, config):
config.retry_times = 2
config.raw = True
@ -256,6 +271,13 @@ def test_peek_key_not_exist(iredis_client, clean_redis, config):
assert peek_result == ["non-exist-key doesn't exist."]
def test_iredis_with_username():
with patch("redis.connection.Connection.connect"):
c = Client("127.0.0.1", "6379", username="abc", password="abc1")
assert c.connection.username == "abc"
assert c.connection.password == "abc1"
def test_peek_string(iredis_client, clean_redis):
clean_redis.set("foo", "bar")
peek_result = list(iredis_client.do_peek("foo"))
@ -337,12 +359,13 @@ def test_peek_zset_fetch_all(iredis_client, clean_redis):
"myzset", dict(zip([f"hello-{index}" for index in range(3)], range(3)))
)
peek_result = list(iredis_client.do_peek("myzset"))
formatted_text_rematch(
peek_result[0][0:9],
FormattedText(
[
("class:dockey", "key: "),
("", r"zset \(ziplist\) mem: \d+ bytes, ttl: -1"),
("", rf"zset \({zset_type}\) mem: \d+ bytes, ttl: -1"),
("", "\n"),
("class:dockey", "zcount: "),
("", "3"),
@ -365,7 +388,7 @@ def test_peek_zset_fetch_part(iredis_client, clean_redis):
FormattedText(
[
("class:dockey", "key: "),
("", r"zset \(ziplist\) mem: \d+ bytes, ttl: -1"),
("", rf"zset \({zset_type}\) mem: \d+ bytes, ttl: -1"),
("", "\n"),
("class:dockey", "zcount: "),
("", "40"),
@ -527,29 +550,23 @@ def test_version_parse_for_auth(iredis_client):
"info, version",
[
(
(
"# Server\r\nredis_version:df--128-NOTFOUND\r\n"
"redis_mode:standalone\r\narch_bits:64"
),
"# Server\r\nredis_version:df--128-NOTFOUND\r\n"
"redis_mode:standalone\r\narch_bits:64",
"df--128-NOTFOUND",
),
(
(
"# Server\r\nredis_version:6.2.5\r\n"
"redis_git_sha1:00000000\r\n"
"redis_git_dirty:0\r\n"
"redis_build_id:915e5480613bc9b6\r\n"
"redis_mode:standalone "
),
"# Server\r\nredis_version:6.2.5\r\n"
"redis_git_sha1:00000000\r\n"
"redis_git_dirty:0\r\n"
"redis_build_id:915e5480613bc9b6\r\n"
"redis_mode:standalone ",
"6.2.5",
),
(
(
"# Server\r\nredis_version:5.0.14.1\r\n"
"redis_git_sha1:00000000\r\nredis_git_dirty:0\r\n"
"redis_build_id:915e5480613bc9b6\r\n"
"redis_mode:standalone "
),
"# Server\r\nredis_version:5.0.14.1\r\n"
"redis_git_sha1:00000000\r\nredis_git_dirty:0\r\n"
"redis_build_id:915e5480613bc9b6\r\n"
"redis_mode:standalone ",
"5.0.14.1",
),
],
@ -564,3 +581,22 @@ def test_version_path(info, version):
client = Client("127.0.0.1", "6379", None)
client.get_server_info()
assert mock_config.version == version
def test_prompt():
c = Client()
assert str(c) == "127.0.0.1:6379> "
c = Client(prompt="{host} {port} {db}")
assert str(c) == "127.0.0.1 6379 0"
c = Client(prompt="{host} {port} {db} {username}")
assert str(c) == "127.0.0.1 6379 0 None"
c = Client(prompt="{host} {port} {db} {username}", username="foo1")
assert str(c) == "127.0.0.1 6379 0 foo1"
c = Client(prompt="{client_id} aabc")
assert re.match(r"^\d+ aabc$", str(c))
c = Client(prompt="{client_addr} >")
assert re.match(r"^127.0.0.1:\d+ >$", str(c))