Merging upstream version 1.12.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
d6445459ac
commit
7865f9a813
20 changed files with 536 additions and 80 deletions
|
@ -1,5 +1,5 @@
|
|||
[bumpversion]
|
||||
current_version = 1.11.1
|
||||
current_version = 1.12.0
|
||||
commit = True
|
||||
tag = True
|
||||
|
||||
|
|
2
.github/workflows/test.yaml
vendored
2
.github/workflows/test.yaml
vendored
|
@ -49,7 +49,7 @@ jobs:
|
|||
REDIS_VERSION: ${{ matrix.redis }}
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
pytest || cat cli_test.log
|
||||
pytest
|
||||
lint:
|
||||
name: flake8 & black
|
||||
runs-on: ubuntu-latest
|
||||
|
|
29
CHANGELOG.md
29
CHANGELOG.md
|
@ -1,4 +1,25 @@
|
|||
## 1.11.1
|
||||
## 1.12
|
||||
|
||||
- Feature: `CLIENT KILL` now support `LADDR` argument.
|
||||
- Feature: `CLIENT LIST` now support `ID` argument.
|
||||
- Feature: `CLIENT PAUSE` support options and added `CLIENT UNPAUSE` command.
|
||||
- Feature: `CLIENT TRACKING` support multiple prefixes.
|
||||
- Feature: support new command: `CLIENT TRACKINGINFO`.
|
||||
- Feature: support new command: `COPY`.
|
||||
- Feature: support new command: `EVAL_RO` and `EVALSHA_RO`.
|
||||
- Feature: support new command: `EXPIRETIME`.
|
||||
- Feature: support new command: `FAILOVER`.
|
||||
- Feature: support new command: `GEOSEARCH`.
|
||||
- Feature: support new command: `GEOSEARCHRESTORE`.
|
||||
- Feature: support new command: `GETDEL`.
|
||||
- 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.
|
||||
|
||||
### 1.11.1
|
||||
|
||||
- Bugfix: Switch `distutils.version` to `packaging.version` to fix the version parse
|
||||
for windows. (new dependency: pypi's python-packaging.
|
||||
|
@ -16,6 +37,12 @@
|
|||
command like `BLPOP`.
|
||||
- Test: IRedis now tested under ubuntu-latest (before is ubuntu-16.04)
|
||||
- Dependency: Support Python 3.10 now, thanks to [tssujt].
|
||||
- Add new command group: `bitmap`.
|
||||
- Support new command in Redis:
|
||||
- `ACL GETUSER`
|
||||
- `ACL HELP`
|
||||
- `BLMOVE`
|
||||
- `CLIENT INFO`
|
||||
|
||||
### 1.9.4
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = "1.11.1"
|
||||
__version__ = "1.12.0"
|
||||
|
|
|
@ -186,9 +186,7 @@ class Client:
|
|||
def get_server_info(self):
|
||||
# safe to decode Redis's INFO response
|
||||
info_resp = nativestr(self.execute("INFO"))
|
||||
version = re.findall(r"^redis_version:([\d\.]+)\r\n", info_resp, re.MULTILINE)[
|
||||
0
|
||||
]
|
||||
version = re.findall(r"redis_version:(.+)\r\n", info_resp)[0]
|
||||
logger.debug(f"[Redis Version] {version}")
|
||||
config.version = version
|
||||
|
||||
|
|
|
@ -79,6 +79,15 @@ class TimestampCompleter(Completer):
|
|||
The timezone is read from system.
|
||||
"""
|
||||
|
||||
def __init__(self, is_milliseconds, future_time, *args, **kwargs):
|
||||
if is_milliseconds:
|
||||
self.factor = 1000
|
||||
else:
|
||||
self.factor = 1
|
||||
|
||||
self.future_time = future_time
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
when_lower_than = {
|
||||
"year": 20,
|
||||
"month": 12,
|
||||
|
@ -96,10 +105,17 @@ class TimestampCompleter(Completer):
|
|||
now = pendulum.now()
|
||||
for unit, minimum in self.when_lower_than.items():
|
||||
if current <= minimum:
|
||||
dt = now.subtract(**{f"{unit}s": current})
|
||||
meta = f"{text} {unit}{'s' if current > 1 else ''} ago ({dt.format('YYYY-MM-DD HH:mm:ss')})"
|
||||
|
||||
if self.future_time:
|
||||
dt = now.add(**{f"{unit}s": current})
|
||||
offset_text = "later"
|
||||
else:
|
||||
dt = now.subtract(**{f"{unit}s": current})
|
||||
offset_text = "ago"
|
||||
|
||||
meta = f"{text} {unit}{'s' if current > 1 else ''} {offset_text} ({dt.format('YYYY-MM-DD HH:mm:ss')})"
|
||||
yield Completion(
|
||||
str(dt.int_timestamp * 1000),
|
||||
str(dt.int_timestamp * self.factor),
|
||||
start_position=-len(document.text_before_cursor),
|
||||
display_meta=meta,
|
||||
)
|
||||
|
@ -111,7 +127,7 @@ class TimestampCompleter(Completer):
|
|||
except Exception:
|
||||
return
|
||||
yield Completion(
|
||||
str(dt.int_timestamp * 1000),
|
||||
str(dt.int_timestamp * self.factor),
|
||||
start_position=-len(document.text_before_cursor),
|
||||
display_meta=str(dt),
|
||||
)
|
||||
|
@ -296,7 +312,16 @@ class IRedisCompleter(Completer):
|
|||
config.completer_max, []
|
||||
)
|
||||
categoryname_completer = MostRecentlyUsedFirstWordCompleter(100, [])
|
||||
timestamp_completer = TimestampCompleter()
|
||||
|
||||
timestamp_ms_ago_completer = TimestampCompleter(
|
||||
is_milliseconds=True, future_time=False
|
||||
)
|
||||
timestamp_ms_after_completer = TimestampCompleter(
|
||||
is_milliseconds=True, future_time=True
|
||||
)
|
||||
timestamp_after_completer = TimestampCompleter(
|
||||
is_milliseconds=False, future_time=True
|
||||
)
|
||||
integer_type_completer = IntegerTypeCompleter()
|
||||
|
||||
completer_mapping.update(
|
||||
|
@ -317,7 +342,9 @@ class IRedisCompleter(Completer):
|
|||
# stream groups
|
||||
"group": group_completer,
|
||||
# stream id
|
||||
"stream_id": timestamp_completer,
|
||||
"stream_id": timestamp_ms_ago_completer,
|
||||
"timestampms": timestamp_ms_after_completer,
|
||||
"timestamp": timestamp_after_completer,
|
||||
"inttype": integer_type_completer,
|
||||
"categoryname": categoryname_completer,
|
||||
"username": username_completer,
|
||||
|
|
|
@ -32,19 +32,24 @@ connection,SELECT,command_index,render_simple_string
|
|||
connection,CLIENT CACHING,command_yes,render_simple_string
|
||||
connection,CLIENT GETREDIR,command,render_int
|
||||
connection,CLIENT TRACKING,command_client_tracking,render_simple_string
|
||||
connection,CLIENT LIST,command_type_conntype_x,render_bulk_string_decode
|
||||
connection,CLIENT TRACKINGINFO,command,render_list
|
||||
connection,CLIENT LIST,command_client_list,render_bulk_string_decode
|
||||
connection,CLIENT GETNAME,command,render_bulk_string
|
||||
connection,CLIENT ID,command,render_int
|
||||
connection,CLIENT INFO,command,render_bulk_string_decode
|
||||
connection,CLIENT KILL,command_clientkill,render_string_or_int
|
||||
connection,CLIENT PAUSE,command_timeout,render_simple_string
|
||||
connection,CLIENT PAUSE,command_pause,render_simple_string
|
||||
connection,CLIENT UNPAUSE,command,render_simple_string
|
||||
connection,CLIENT REPLY,command_switch,render_simple_string
|
||||
connection,CLIENT SETNAME,command_value,render_simple_string
|
||||
connection,CLIENT UNBLOCK,command_clientid_errorx,render_int
|
||||
generic,COPY,command_copy,render_int
|
||||
generic,DEL,command_keys,render_int
|
||||
generic,DUMP,command_key,render_bulk_string
|
||||
generic,EXISTS,command_keys,render_int
|
||||
generic,EXPIRE,command_key_second,render_int
|
||||
generic,EXPIREAT,command_key_timestamp,render_int
|
||||
generic,EXPIRETIME,command_key,render_int
|
||||
generic,KEYS,command_pattern,command_keys
|
||||
generic,MIGRATE,command_migrate,render_simple_string
|
||||
generic,MOVE,command_key_index,render_int
|
||||
|
@ -68,8 +73,10 @@ geo,GEOADD,command_key_longitude_latitude_members,render_int
|
|||
geo,GEODIST,command_geodist,render_bulk_string
|
||||
geo,GEOHASH,command_key_members,render_list
|
||||
geo,GEOPOS,command_key_members,render_list
|
||||
geo,GEORADIUS,command_radius,render_list_or_string
|
||||
geo,GEORADIUSBYMEMBER,command_georadiusbymember,render_list_or_string
|
||||
geo,GEORADIUS,command_any,render_list_or_string
|
||||
geo,GEORADIUSBYMEMBER,command_any,render_list_or_string
|
||||
geo,GEOSEARCH,command_key_any,render_list
|
||||
geo,GEOSEARCHSTORE,command_key_key_any,render_list
|
||||
hash,HDEL,command_key_fields,render_int
|
||||
hash,HEXISTS,command_key_field,render_int
|
||||
hash,HGET,command_key_field,render_bulk_string
|
||||
|
@ -88,6 +95,7 @@ hash,HVALS,command_key,render_list
|
|||
hyperloglog,PFADD,command_key_values,render_int
|
||||
hyperloglog,PFCOUNT,command_keys,render_int
|
||||
hyperloglog,PFMERGE,command_newkey_keys,render_simple_string
|
||||
list,BLMOVE,command_key_key_lr_lr_timeout, render_bulk_string
|
||||
list,BLPOP,command_keys_timeout,render_list_or_string
|
||||
list,BRPOP,command_keys_timeout,render_list_or_string
|
||||
list,BRPOPLPUSH,command_key_newkey_timeout,render_bulk_string
|
||||
|
@ -113,7 +121,9 @@ pubsub,PUNSUBSCRIBE,command_channels,render_subscribe
|
|||
pubsub,SUBSCRIBE,command_channels,render_subscribe
|
||||
pubsub,UNSUBSCRIBE,command_channels,render_subscribe
|
||||
scripting,EVAL,command_lua_any,render_list_or_string
|
||||
scripting,EVAL_RO,command_lua_any,render_list_or_string
|
||||
scripting,EVALSHA,command_any,render_list_or_string
|
||||
scripting,EVALSHA_RO,command_any,render_list_or_string
|
||||
scripting,SCRIPT DEBUG,command_scriptdebug,render_simple_string
|
||||
scripting,SCRIPT EXISTS,command_any,render_list
|
||||
scripting,SCRIPT FLUSH,command,render_simple_string
|
||||
|
@ -145,6 +155,7 @@ server,CONFIG SET,command_parameter_value,render_simple_string
|
|||
server,DBSIZE,command,render_int
|
||||
server,DEBUG OBJECT,command_key,render_simple_string
|
||||
server,DEBUG SEGFAULT,command,render_simple_string
|
||||
server,FAILOVER,command_failover,render_simple_string
|
||||
server,FLUSHALL,command_asyncx,render_simple_string
|
||||
server,FLUSHDB,command_asyncx,render_simple_string
|
||||
server,INFO,command_sectionx,render_bulk_string_decode
|
||||
|
@ -229,14 +240,16 @@ stream,XREADGROUP,command_xreadgroup,render_list
|
|||
stream,XREVRANGE,command_key_start_end_countx,render_list
|
||||
stream,XTRIM,command_key_maxlen,render_int
|
||||
string,APPEND,command_key_value,render_int
|
||||
string,BITCOUNT,command_key_start_end_x,render_int
|
||||
string,BITFIELD,command_bitfield,render_list
|
||||
string,BITOP,command_operation_key_keys,render_int
|
||||
string,BITPOS,command_key_bit_start_end,render_int
|
||||
bitmap,BITCOUNT,command_key_start_end_x,render_int
|
||||
bitmap,BITFIELD,command_bitfield,render_list
|
||||
bitmap,BITOP,command_operation_key_keys,render_int
|
||||
bitmap,BITPOS,command_key_bit_start_end,render_int
|
||||
string,DECR,command_key,render_int
|
||||
string,DECRBY,command_key_delta,render_int
|
||||
string,GET,command_key,render_bulk_string
|
||||
string,GETEX,command_key_expire,render_bulk_string
|
||||
string,GETBIT,command_key_offset,render_int
|
||||
string,GETDEL,command_key,render_bulk_string
|
||||
string,GETRANGE,command_key_start_end,render_bulk_string
|
||||
string,GETSET,command_key_value,render_bulk_string
|
||||
string,INCR,command_key,render_int
|
||||
|
|
|
|
@ -18,6 +18,8 @@ CONST = {
|
|||
"withscores": "WITHSCORES",
|
||||
"limit": "LIMIT",
|
||||
"expiration": "EX PX",
|
||||
"exat_const": "EXAT",
|
||||
"pxat_const": "PXAT",
|
||||
"condition": "NX XX",
|
||||
"keepttl": "KEEPTTL",
|
||||
"operation": "AND OR XOR NOT",
|
||||
|
@ -32,7 +34,7 @@ CONST = {
|
|||
"type": "string list set zset hash stream",
|
||||
"position_choice": "BEFORE AFTER",
|
||||
"error": "TIMEOUT ERROR",
|
||||
"async": "ASYNC",
|
||||
"async": "ASYNC SYNC",
|
||||
"conntype": "NORMAL MASTER REPLICA PUBSUB",
|
||||
"samples": "SAMPLES",
|
||||
"slotsubcmd": "IMPORTING MIGRATING NODE STABLE",
|
||||
|
@ -45,6 +47,7 @@ CONST = {
|
|||
"on_off": "ON OFF",
|
||||
"const_id": "ID",
|
||||
"addr": "ADDR",
|
||||
"laddr": "LADDR",
|
||||
"skipme": "SKIPME",
|
||||
"yes": "YES NO",
|
||||
"migratechoice": "COPY REPLACE",
|
||||
|
@ -130,6 +133,13 @@ CONST = {
|
|||
"withmatchlen_const": "WITHMATCHLEN",
|
||||
"strings_const": "STRINGS",
|
||||
"rank_const": "RANK",
|
||||
"lr_const": "LEFT RIGHT",
|
||||
"pause_type": "WRITE ALL",
|
||||
"db_const": "DB",
|
||||
"replace_const": "REPLACE",
|
||||
"to_const": "TO",
|
||||
"timeout_const": "TIMEOUT",
|
||||
"abort_const": "ABORT",
|
||||
}
|
||||
|
||||
|
||||
|
@ -151,14 +161,16 @@ VALID_NODE = r"\w+"
|
|||
NUM = r"\d+"
|
||||
NNUM = r"-?\+?\(?\[?(\d+|inf)" # number cloud be negative
|
||||
_FLOAT = r"-?(\d|\.|e)+"
|
||||
DOUBLE = r"\d*(\.\d+)?"
|
||||
LEXNUM = r"(\[\w+)|(\(\w+)|(\+)|(-)"
|
||||
|
||||
SLOT = rf"(?P<slot>{VALID_SLOT})"
|
||||
SLOTS = rf"(?P<slots>{VALID_SLOT}(\s+{VALID_SLOT})*)"
|
||||
NODE = rf"(?P<node>{VALID_NODE})"
|
||||
KEY = rf"(?P<key>{VALID_TOKEN})"
|
||||
PREFIX = rf"(?P<prefix>{VALID_TOKEN})"
|
||||
KEYS = rf"(?P<keys>{VALID_TOKEN}(\s+{VALID_TOKEN})*)"
|
||||
PREFIX = rf"(?P<prefix>{VALID_TOKEN})"
|
||||
PREFIXES = rf"(?P<prefixes>{VALID_TOKEN}(\s+{VALID_TOKEN})*?)"
|
||||
DESTINATION = rf"(?P<destination>{VALID_TOKEN})"
|
||||
NEWKEY = rf"(?P<newkey>{VALID_TOKEN})"
|
||||
VALUE = rf"(?P<value>{VALID_TOKEN})"
|
||||
|
@ -205,13 +217,15 @@ PASSWORD = rf"(?P<password>{VALID_TOKEN})"
|
|||
REPLICATIONID = rf"(?P<replicationid>{VALID_TOKEN})"
|
||||
INDEX = r"(?P<index>(1[0-5]|\d))"
|
||||
CLIENTID = rf"(?P<clientid>{NUM})"
|
||||
CLIENTIDS = rf"(?P<clientids>{NUM}(\s+{NUM})*)"
|
||||
|
||||
SECOND = rf"(?P<second>{NUM})"
|
||||
TIMESTAMP = rf"(?P<timestamp>{NUM})"
|
||||
TIMESTAMP = r"(?P<timestamp>[T\d:>+*\-\$]+)"
|
||||
# TODO test lexer & completer for multi spaces in command
|
||||
# For now, redis command can have one space at most
|
||||
COMMAND = "(\s* (?P<command>[\w -]+))"
|
||||
COMMAND = r"(\s* (?P<command>[\w -]+))"
|
||||
MILLISECOND = rf"(?P<millisecond>{NUM})"
|
||||
TIMESTAMPMS = rf"(?P<timestampms>{NUM})"
|
||||
TIMESTAMPMS = r"(?P<timestampms>[T\d:>+*\-\$]+)"
|
||||
ANY = r"(?P<any>.*)" # TODO deleted
|
||||
START = rf"(?P<start>{NNUM})"
|
||||
END = rf"(?P<end>{NNUM})"
|
||||
|
@ -221,15 +235,24 @@ END = rf"(?P<end>{NNUM})"
|
|||
# https://redis.io/topics/streams-intro#special-ids-in-the-streams-api
|
||||
# stream id, DO NOT use r"" here, or the \+ will be two string
|
||||
# NOTE: if miss the outer (), multi IDS won't work.
|
||||
STREAM_ID = "(?P<stream_id>[T\d:>+*\-\$]+)"
|
||||
STREAM_ID = r"(?P<stream_id>[T\d:>+*\-\$]+)"
|
||||
|
||||
DELTA = rf"(?P<delta>{NNUM})"
|
||||
OFFSET = rf"(?P<offset>{NUM})" # string offset, can't be negative
|
||||
SHARP_OFFSET = f"(?P<offset>\#?{NUM})" # for bitfield command
|
||||
SHARP_OFFSET = rf"(?P<offset>\#?{NUM})" # for bitfield command
|
||||
MIN = rf"(?P<min>{NNUM})"
|
||||
MAX = rf"(?P<max>{NNUM})"
|
||||
POSITION = rf"(?P<position>{NNUM})"
|
||||
TIMEOUT = rf"(?P<timeout>{NUM})"
|
||||
SCORE = rf"(?P<score>{_FLOAT})"
|
||||
LEXMIN = rf"(?P<lexmin>{LEXNUM})"
|
||||
LEXMAX = rf"(?P<lexmax>{LEXNUM})"
|
||||
WEIGHTS = rf"(?P<weights>{_FLOAT}(\s+{_FLOAT})*)"
|
||||
IP_PORT = rf"(?P<ip_port>{IP}:{PORT})"
|
||||
HOST = rf"(?P<host>{VALID_TOKEN})"
|
||||
MIN = rf"(?P<min>{NNUM})"
|
||||
MAX = rf"(?P<max>{NNUM})"
|
||||
POSITION = rf"(?P<position>{NNUM})"
|
||||
TIMEOUT = rf"(?P<timeout>{DOUBLE})"
|
||||
SCORE = rf"(?P<score>{_FLOAT})"
|
||||
LEXMIN = rf"(?P<lexmin>{LEXNUM})"
|
||||
LEXMAX = rf"(?P<lexmax>{LEXNUM})"
|
||||
|
@ -267,6 +290,7 @@ ON_OFF = rf"(?P<on_off>{c('on_off')})"
|
|||
CONST_ID = rf"(?P<const_id>{c('const_id')})"
|
||||
CONST_USER = rf"(?P<const_user>{c('const_user')})"
|
||||
ADDR = rf"(?P<addr>{c('addr')})"
|
||||
LADDR = rf"(?P<laddr>{c('laddr')})"
|
||||
SKIPME = rf"(?P<skipme>{c('skipme')})"
|
||||
YES = rf"(?P<yes>{c('yes')})"
|
||||
MIGRATECHOICE = rf"(?P<migratechoice>{c('migratechoice')})"
|
||||
|
@ -329,6 +353,16 @@ WITHMATCHLEN_CONST = rf"(?P<withmatchlen_const>{c('withmatchlen_const')})"
|
|||
STRINGS_CONST = rf"(?P<strings_const>{c('strings_const')})"
|
||||
RANK_CONST = rf"(?P<rank_const>{c('rank_const')})"
|
||||
|
||||
LR_CONST = rf"(?P<lr_const>{c('lr_const')})"
|
||||
PAUSE_TYPE = rf"(?P<pause_type>{c('pause_type')})"
|
||||
DB_CONST = rf"(?P<db_const>{c('db_const')})"
|
||||
REPLACE_CONST = rf"(?P<replace_const>{c('replace_const')})"
|
||||
TO_CONST = rf"(?P<to_const>{c('to_const')})"
|
||||
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')})"
|
||||
|
||||
command_grammar = compile(COMMAND)
|
||||
|
||||
# Here are the core grammars, those are tokens after ``command``.
|
||||
|
@ -339,14 +373,6 @@ command_grammar = compile(COMMAND)
|
|||
GRAMMAR = {
|
||||
"command_key": rf"\s+ {KEY} \s*",
|
||||
"command_pattern": rf"\s+ {PATTERN} \s*",
|
||||
"command_georadiusbymember": rf"""
|
||||
\s+ {KEY} \s+ {MEMBER}
|
||||
\s+ {FLOAT} \s+ {DISTUNIT}
|
||||
(\s+ {GEOCHOICE})*
|
||||
(\s+ {COUNT_CONST} \s+ {COUNT})?
|
||||
(\s+ {ORDER})?
|
||||
(\s+ {CONST_STORE} \s+ {KEY})?
|
||||
(\s+ {CONST_STOREDIST} \s+ {KEY})? \s*""",
|
||||
"command_command": rf"\s+ {COMMAND} \s*",
|
||||
"command_slots": rf"\s+ {SLOTS} \s*",
|
||||
"command_node": rf"\s+ {NODE} \s*",
|
||||
|
@ -370,8 +396,12 @@ GRAMMAR = {
|
|||
"command_messagex": rf"(\s+{MESSAGE})? \s*",
|
||||
"command_index": rf"\s+ {INDEX} \s*",
|
||||
"command_index_index": rf"\s+ {INDEX} \s+ {INDEX} \s*",
|
||||
"command_type_conntype_x": rf"""
|
||||
(\s+ {TYPE_CONST} \s+ {CONNTYPE})? \s*""",
|
||||
"command_client_list": rf"""
|
||||
(
|
||||
(\s+ {TYPE_CONST} \s+ {CONNTYPE})|
|
||||
(\s+ {CONST_ID} \s+ {CLIENTIDS})
|
||||
)*
|
||||
\s*""",
|
||||
"command_clientid_errorx": rf"\s+ {CLIENTID} (\s+ {ERROR})? \s*",
|
||||
"command_keys": rf"\s+ {KEYS} \s*",
|
||||
"command_key_value": rf"\s+ {KEY} \s+ {VALUE} \s*",
|
||||
|
@ -388,7 +418,7 @@ GRAMMAR = {
|
|||
"command_key_newkey_timeout": rf"\s+ {KEY} \s+ {NEWKEY} \s+ {TIMEOUT} \s*",
|
||||
"command_keys_timeout": rf"\s+ {KEYS} \s+ {TIMEOUT} \s*",
|
||||
"command_count_timeout": rf"\s+ {COUNT} \s+ {TIMEOUT} \s*",
|
||||
"command_timeout": rf"\s+ {TIMEOUT} \s*",
|
||||
"command_pause": rf"\s+ {TIMEOUT} (\s+ {PAUSE_TYPE})? \s*",
|
||||
"command_key_positionchoice_pivot_value": rf"""
|
||||
\s+ {KEY} \s+ {POSITION_CHOICE} \s+ {VALUE} \s+ {VALUE} \s*""",
|
||||
"command_pass": rf"\s+ {ANY} \s*",
|
||||
|
@ -420,10 +450,16 @@ GRAMMAR = {
|
|||
"command_key_members": rf"\s+ {KEY} \s+ {MEMBERS} \s*",
|
||||
"command_geodist": rf"\s+ {KEY} \s+ {MEMBER} \s+ {MEMBER} (\s+ {DISTUNIT})? \s*",
|
||||
"command_key_longitude_latitude_members": rf"""
|
||||
\s+ {KEY} (\s+ {LONGITUDE} \s+ {LATITUDE} \s {MEMBER})+ \s*""",
|
||||
\s+ {KEY}
|
||||
(\s+ {CONDITION})?
|
||||
(\s+ {CHANGED})?
|
||||
(\s+ {LONGITUDE} \s+ {LATITUDE} \s {MEMBER})+
|
||||
\s*""",
|
||||
"command_destination_keys": rf"\s+ {DESTINATION} \s+ {KEYS} \s*",
|
||||
"command_object_key": rf"\s+ {OBJECT} \s+ {KEY} \s*",
|
||||
"command_key_member": rf"\s+ {KEY} \s+ {MEMBER} \s*",
|
||||
"command_key_any": rf"\s+ {KEY} \s+ {ANY} \s*",
|
||||
"command_key_key_any": rf"\s+ {KEY} \s+ {KEY} \s+ {ANY} \s*",
|
||||
"command_key_newkey_member": rf"\s+ {KEY} \s+ {NEWKEY} \s+ {MEMBER} \s*",
|
||||
"command_key_count_x": rf"\s+ {KEY} (\s+ {COUNT})? \s*",
|
||||
"command_key_min_max": rf"\s+ {KEY} \s+ {MIN} \s+ {MAX} \s*",
|
||||
|
@ -459,6 +495,7 @@ GRAMMAR = {
|
|||
(
|
||||
(\s+ {IP_PORT})|
|
||||
(\s+ {ADDR} \s+ {IP_PORT})|
|
||||
(\s+ {LADDR} \s+ {IP_PORT})|
|
||||
(\s+ {CONST_ID} \s+ {CLIENTID})|
|
||||
(\s+ {TYPE_CONST} \s+ {CONNTYPE})|
|
||||
(\s+ {CONST_USER} \s+ {USERNAME})|
|
||||
|
@ -474,12 +511,6 @@ GRAMMAR = {
|
|||
)?
|
||||
(\s+ {CONST_KEYS} \s+ {KEYS})?
|
||||
\s*""",
|
||||
"command_radius": rf"""\s+ {KEY}
|
||||
\s+ {LONGITUDE} \s+ {LATITUDE} \s+ {FLOAT} \s+ {DISTUNIT}
|
||||
(\s+ {GEOCHOICE})* (\s+ {COUNT_CONST} \s+ {COUNT})?
|
||||
(\s+ {ORDER})?
|
||||
(\s+ {CONST_STORE} \s+ {KEY})?
|
||||
(\s+ {CONST_STOREDIST} \s+ {KEY})? \s*""",
|
||||
"command_restore": rf"""\s+ {KEY}
|
||||
\s+ {TIMEOUT} \s+ {VALUE} (\s+ {SUBRESTORE} \s+ {SECOND})? \s*""",
|
||||
"command_pubsubcmd_channels": rf"\s+ {PUBSUBCMD} (\s+ {CHANNEL})+ \s*",
|
||||
|
@ -573,7 +604,7 @@ GRAMMAR = {
|
|||
\s+ {ON_OFF}
|
||||
(
|
||||
(\s+ {REDIRECT_CONST} \s+ {CLIENTID})|
|
||||
(\s+ {PREFIX_CONST} \s+ {PREFIX})|
|
||||
(\s+ {PREFIX_CONST} \s+ {PREFIXES})|
|
||||
(\s+ {BCAST_CONST})|
|
||||
(\s+ {OPTIN_CONST})|
|
||||
(\s+ {OPTOUT_CONST})|
|
||||
|
@ -607,6 +638,28 @@ GRAMMAR = {
|
|||
(\s+ {MAXLEN} \s+ {LEN})
|
||||
)*
|
||||
\s*""",
|
||||
"command_key_key_lr_lr_timeout": rf"""
|
||||
\s+ {KEY} \s+ {KEY}
|
||||
\s+ {LR_CONST} \s+ {LR_CONST}
|
||||
\s+ {TIMEOUT} \s*""",
|
||||
"command_copy": rf"""
|
||||
\s+ {KEY} \s+ {KEY}
|
||||
(\s+ {DB_CONST} \s+ {INDEX})?
|
||||
(\s+ {REPLACE_CONST})?
|
||||
\s*""",
|
||||
"command_failover": rf"""
|
||||
(\s+ {TO_CONST} \s+ {HOST} \s+ {PORT} (\s+ {FORCE})? )?
|
||||
(\s+ {ABORT_CONST})?
|
||||
(\s+ {TIMEOUT_CONST} \s+ {MILLISECOND})?
|
||||
\s*""",
|
||||
"command_key_expire": rf"""
|
||||
\s+ {KEY}
|
||||
(
|
||||
(\s+ {EXPIRATION} \s+ {MILLISECOND})|
|
||||
(\s+ {PXAT_CONST} \s+ {TIMESTAMPMS})|
|
||||
(\s+ {EXAT_CONST} \s+ {TIMESTAMP})
|
||||
)?
|
||||
\s*""",
|
||||
}
|
||||
|
||||
pipeline = r"(?P<shellcommand>\|.*)?"
|
||||
|
|
|
@ -14,7 +14,7 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
_last_timer = time.time()
|
||||
_timer_counter = 0
|
||||
sperator = re.compile(r"\s")
|
||||
separator = re.compile(r"\s")
|
||||
logger.debug(f"[timer] start on {_last_timer}")
|
||||
|
||||
|
||||
|
@ -73,8 +73,8 @@ def strip_quote_args(s):
|
|||
word.append(char)
|
||||
# not in quote
|
||||
else:
|
||||
# sperator
|
||||
if sperator.match(char):
|
||||
# separator
|
||||
if separator.match(char):
|
||||
if word:
|
||||
yield "".join(word)
|
||||
word = []
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "iredis"
|
||||
version = "1.11.1"
|
||||
version = "1.12.0"
|
||||
description = "Terminal client for Redis with auto-completion and syntax highlighting."
|
||||
authors = ["laixintao <laixintao1995@163.com>"]
|
||||
readme = 'README.md'
|
||||
|
@ -52,5 +52,5 @@ pexpect = "^4.7"
|
|||
iredis = 'iredis.entry:main'
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
build-backend = "poetry.masonry.api"
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
|
|
@ -61,6 +61,7 @@ def test_hello_command_is_not_supported(cli):
|
|||
cli.expect("IRedis currently not support RESP3")
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="unstable, maybe due to github action's signal handling")
|
||||
def test_abort_reading_connection(cli):
|
||||
cli.sendline("blpop mylist 30")
|
||||
cli.send(chr(3))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import os
|
||||
import re
|
||||
import tempfile
|
||||
from textwrap import dedent
|
||||
|
||||
|
@ -17,6 +18,22 @@ TIMEOUT = 2
|
|||
HISTORY_FILE = ".iredis_history"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def token_should_match():
|
||||
def match_func(token, tomatch):
|
||||
assert re.fullmatch(token, tomatch) is not None
|
||||
|
||||
return match_func
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def token_should_not_match():
|
||||
def match_func(token, tomatch):
|
||||
assert re.fullmatch(token, tomatch) is None
|
||||
|
||||
return match_func
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def judge_command():
|
||||
def judge_command_func(input_text, expect):
|
||||
|
|
|
@ -54,3 +54,27 @@ def test_command_with_key_in_quotes(judge_command):
|
|||
judge_command(
|
||||
'cluster keyslot "mykey "', {"command": "cluster keyslot", "key": '"mykey "'}
|
||||
)
|
||||
|
||||
|
||||
def test_timeout(token_should_match, token_should_not_match):
|
||||
from iredis.redis_grammar import TIMEOUT
|
||||
|
||||
token_should_match(TIMEOUT, "1.1")
|
||||
token_should_match(TIMEOUT, "1.0")
|
||||
token_should_match(TIMEOUT, ".1")
|
||||
token_should_match(TIMEOUT, "123123.1123")
|
||||
token_should_not_match(TIMEOUT, "1.")
|
||||
token_should_not_match(TIMEOUT, ".")
|
||||
token_should_not_match(TIMEOUT, ".a")
|
||||
|
||||
|
||||
def test_lr_const(token_should_match, token_should_not_match):
|
||||
from iredis.redis_grammar import LR_CONST
|
||||
|
||||
token_should_match(LR_CONST, "left")
|
||||
token_should_match(LR_CONST, "right")
|
||||
token_should_match(LR_CONST, "LEFT")
|
||||
token_should_match(LR_CONST, "RIGHT")
|
||||
token_should_not_match(LR_CONST, "righ")
|
||||
token_should_not_match(LR_CONST, "ab")
|
||||
token_should_not_match(LR_CONST, "123")
|
||||
|
|
|
@ -71,7 +71,7 @@ def test_client_tracking(judge_command):
|
|||
"command": "CLIENT TRACKING",
|
||||
"on_off": "ON",
|
||||
"prefix_const": "PREFIX",
|
||||
"prefix": "foo",
|
||||
"prefixes": "foo",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
|
@ -80,7 +80,7 @@ def test_client_tracking(judge_command):
|
|||
"command": "CLIENT TRACKING",
|
||||
"on_off": "ON",
|
||||
"prefix_const": "PREFIX",
|
||||
"prefix": "foo",
|
||||
"prefixes": "foo",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
|
@ -89,9 +89,28 @@ def test_client_tracking(judge_command):
|
|||
"command": "CLIENT TRACKING",
|
||||
"on_off": "ON",
|
||||
"prefix_const": "PREFIX",
|
||||
"prefix": "foo",
|
||||
"prefixes": "foo",
|
||||
"bcast_const": "BCAST",
|
||||
"noloop_const": "NOLOOP",
|
||||
"optin_const": "OPTIN",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT TRACKING ON PREFIX foo bar ok BCAST NOLOOP OPTIN",
|
||||
{
|
||||
"command": "CLIENT TRACKING",
|
||||
"on_off": "ON",
|
||||
"prefix_const": "PREFIX",
|
||||
"prefixes": "foo bar ok",
|
||||
"bcast_const": "BCAST",
|
||||
"noloop_const": "NOLOOP",
|
||||
"optin_const": "OPTIN",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_client_pause(judge_command):
|
||||
judge_command(
|
||||
"CLIENT PAUSE 20 WRITE",
|
||||
{"command": "CLIENT PAUSE", "timeout": "20", "pause_type": "WRITE"},
|
||||
)
|
||||
|
|
|
@ -177,3 +177,42 @@ def test_restore(judge_command):
|
|||
"value": '"\n\x17\x17\x00\x00\x00\x12\x00\x00\x00\x03\x00\x00\xc0\x01\x00\x04\xc0\x02\x00\x04\xc0\x03\x00\xff\x04\x00u#<\xc0;.\xe9\xdd"', # noqa
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_copy(judge_command):
|
||||
judge_command(
|
||||
"COPY foo bar DB 3 REPLACE",
|
||||
{
|
||||
"command": "COPY",
|
||||
"key": ["foo", "bar"],
|
||||
"db_const": "DB",
|
||||
"index": "3",
|
||||
"replace_const": "REPLACE",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"COPY foo bar REPLACE",
|
||||
{"command": "COPY", "key": ["foo", "bar"], "replace_const": "REPLACE"},
|
||||
)
|
||||
judge_command("COPY foo bar", {"command": "COPY", "key": ["foo", "bar"]})
|
||||
|
||||
|
||||
def test_getex(judge_command):
|
||||
judge_command("GETEX foo", {"command": "GETEX", "key": "foo"})
|
||||
judge_command(
|
||||
"GETEX bar ex 5",
|
||||
{"command": "GETEX", "key": "bar", "expiration": "ex", "millisecond": "5"},
|
||||
)
|
||||
judge_command(
|
||||
"GETEX bar px 5",
|
||||
{"command": "GETEX", "key": "bar", "expiration": "px", "millisecond": "5"},
|
||||
)
|
||||
judge_command(
|
||||
"GETEX bar pxat 5",
|
||||
{"command": "GETEX", "key": "bar", "pxat_const": "pxat", "timestampms": "5"},
|
||||
)
|
||||
judge_command(
|
||||
"GETEX bar exat 5",
|
||||
{"command": "GETEX", "key": "bar", "exat_const": "exat", "timestamp": "5"},
|
||||
)
|
||||
judge_command("GETEX bar ex 5 exat 5", None)
|
||||
|
|
|
@ -9,31 +9,37 @@ def test_geoadd(judge_command):
|
|||
"member": '"Catania"',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_georadiusbymember(judge_command):
|
||||
judge_command(
|
||||
"GEORADIUSBYMEMBER Sicily Agrigento 100 km",
|
||||
'GEOADD Sicily NX CH 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"',
|
||||
{
|
||||
"command": "GEORADIUSBYMEMBER",
|
||||
"command": "GEOADD",
|
||||
"condition": "NX",
|
||||
"changed": "CH",
|
||||
"key": "Sicily",
|
||||
"member": "Agrigento",
|
||||
"float": "100",
|
||||
"distunit": "km",
|
||||
"longitude": "15.087269",
|
||||
"latitude": "37.502669",
|
||||
"member": '"Catania"',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_georadius(judge_command):
|
||||
def test_geosearch(judge_command):
|
||||
judge_command(
|
||||
"GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD ",
|
||||
"GEOSEARCH Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST",
|
||||
{
|
||||
"command": "GEORADIUS",
|
||||
"command": "GEOSEARCH",
|
||||
"key": "Sicily",
|
||||
"longitude": "15",
|
||||
"latitude": "37",
|
||||
"float": "200",
|
||||
"distunit": "km",
|
||||
"geochoice": "WITHCOORD",
|
||||
"any": "FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_geosearchstore(judge_command):
|
||||
judge_command(
|
||||
"GEOSEARCHSTORE key2 Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3 STOREDIST",
|
||||
{
|
||||
"command": "GEOSEARCHSTORE",
|
||||
"key": ["Sicily", "key2"],
|
||||
"any": "FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3 STOREDIST",
|
||||
},
|
||||
)
|
||||
|
|
|
@ -41,6 +41,18 @@ def test_brpoplpush(judge_command):
|
|||
judge_command("BRPOPLPUSH list1 list2 -1", None)
|
||||
|
||||
|
||||
def test_brpoplpush_with_double_timeout(judge_command):
|
||||
judge_command(
|
||||
"BRPOPLPUSH list1 list2 10.0",
|
||||
{"command": "BRPOPLPUSH", "key": "list1", "newkey": "list2", "timeout": "10.0"},
|
||||
)
|
||||
judge_command(
|
||||
"BRPOPLPUSH list1 list2 .2",
|
||||
{"command": "BRPOPLPUSH", "key": "list1", "newkey": "list2", "timeout": ".2"},
|
||||
)
|
||||
judge_command("BRPOPLPUSH list1 list2 12.", None)
|
||||
|
||||
|
||||
def test_linsert(judge_command):
|
||||
judge_command(
|
||||
'LINSERT mylist BEFORE "World" "There"',
|
||||
|
@ -106,3 +118,26 @@ def test_lpos(judge_command):
|
|||
"rank": "-1",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_blmove(judge_command):
|
||||
judge_command(
|
||||
"blmove list1 list2 left right 1.2",
|
||||
{
|
||||
"command": "blmove",
|
||||
"key": ["list1", "list2"],
|
||||
"lr_const": ["left", "right"],
|
||||
"timeout": "1.2",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"blmove list1 list2 right right .2",
|
||||
{
|
||||
"command": "blmove",
|
||||
"key": ["list1", "list2"],
|
||||
"lr_const": ["right", "right"],
|
||||
"timeout": ".2",
|
||||
},
|
||||
)
|
||||
judge_command("blmove list1 list2 right right", None)
|
||||
judge_command("blmove list1 right right 1", None)
|
||||
|
|
|
@ -31,6 +31,20 @@ def test_client_list(judge_command):
|
|||
{"command": "client list", "type_const": "TYPE", "conntype": "REPLICA"},
|
||||
)
|
||||
|
||||
judge_command(
|
||||
"client list TYPE REPLICA id 1 2 3",
|
||||
{
|
||||
"command": "client list",
|
||||
"type_const": "TYPE",
|
||||
"conntype": "REPLICA",
|
||||
"clientids": "1 2 3",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"client list ID 1 2 3",
|
||||
{"command": "client list", "clientids": "1 2 3"},
|
||||
)
|
||||
|
||||
|
||||
def test_configset(judge_command):
|
||||
judge_command(
|
||||
|
@ -71,6 +85,18 @@ def test_client_kill(judge_command):
|
|||
"CLIENT KILL 127.0.0.1:12345 ",
|
||||
{"command": "CLIENT KILL", "ip_port": "127.0.0.1:12345"},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT KILL ADDR 127.0.0.1:12345 ",
|
||||
{"command": "CLIENT KILL", "ip_port": "127.0.0.1:12345", "addr": "ADDR"},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT KILL LADDR 127.0.0.1:12345 ",
|
||||
{"command": "CLIENT KILL", "ip_port": "127.0.0.1:12345", "laddr": "LADDR"},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT KILL USER myuser",
|
||||
{"command": "CLIENT KILL", "const_user": "USER", "username": "myuser"},
|
||||
)
|
||||
judge_command(
|
||||
"CLIENT KILL id 123455 type pubsub skipme no",
|
||||
{
|
||||
|
@ -199,3 +225,48 @@ def test_acl_setuser(judge_command):
|
|||
def test_acl_getuser(judge_command):
|
||||
judge_command("acl getuser alan", {"command": "acl getuser", "username": "alan"})
|
||||
judge_command("acl getuser", None)
|
||||
|
||||
|
||||
def test_failover(judge_command):
|
||||
judge_command(
|
||||
"failover to 10.0.0.5 7379 abort timeout 101",
|
||||
{
|
||||
"command": "failover",
|
||||
"to_const": "to",
|
||||
"host": "10.0.0.5",
|
||||
"port": "7379",
|
||||
"abort_const": "abort",
|
||||
"timeout_const": "timeout",
|
||||
"millisecond": "101",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"failover abort timeout 101",
|
||||
{
|
||||
"command": "failover",
|
||||
"abort_const": "abort",
|
||||
"timeout_const": "timeout",
|
||||
"millisecond": "101",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"failover timeout 101",
|
||||
{
|
||||
"command": "failover",
|
||||
"timeout_const": "timeout",
|
||||
"millisecond": "101",
|
||||
},
|
||||
)
|
||||
judge_command(
|
||||
"failover to 10.0.0.5 7379 force abort timeout 101",
|
||||
{
|
||||
"command": "failover",
|
||||
"to_const": "to",
|
||||
"force": "force",
|
||||
"host": "10.0.0.5",
|
||||
"port": "7379",
|
||||
"abort_const": "abort",
|
||||
"timeout_const": "timeout",
|
||||
"millisecond": "101",
|
||||
},
|
||||
)
|
||||
|
|
|
@ -33,7 +33,7 @@ def test_send_command(_input, command_name, expect_args):
|
|||
client = Client("127.0.0.1", "6379", None)
|
||||
client.execute = MagicMock()
|
||||
next(client.send_command(_input, None))
|
||||
args, kwargs = client.execute.call_args
|
||||
args, _ = client.execute.call_args
|
||||
assert args == (command_name, *expect_args)
|
||||
|
||||
|
||||
|
@ -511,7 +511,7 @@ def test_reissue_command_on_redis_cluster_with_password_in_dsn(
|
|||
assert call_args[0].password == "bar"
|
||||
|
||||
|
||||
def test_version_parse(iredis_client):
|
||||
def test_version_parse_for_auth(iredis_client):
|
||||
"""
|
||||
fix: https://github.com/laixintao/iredis/issues/418
|
||||
"""
|
||||
|
@ -521,3 +521,46 @@ def test_version_parse(iredis_client):
|
|||
assert command2syntax["AUTH"] == "command_password"
|
||||
iredis_client.auth_compat("5.0.14.1")
|
||||
assert command2syntax["AUTH"] == "command_password"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"info, version",
|
||||
[
|
||||
(
|
||||
(
|
||||
"# 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 "
|
||||
),
|
||||
"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 "
|
||||
),
|
||||
"5.0.14.1",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_version_path(info, version):
|
||||
with patch("iredis.client.config") as mock_config:
|
||||
mock_config.no_info = True
|
||||
mock_config.pager = "less"
|
||||
mock_config.version = "5.0.0"
|
||||
with patch("iredis.client.Client.execute") as mock_execute:
|
||||
mock_execute.return_value = info
|
||||
client = Client("127.0.0.1", "6379", None)
|
||||
client.get_server_info()
|
||||
assert mock_config.version == version
|
||||
|
|
|
@ -183,7 +183,7 @@ def test_group_completer():
|
|||
@patch("iredis.completers.pendulum.now")
|
||||
def test_timestamp_completer_humanize_time_completion(fake_now):
|
||||
fake_now.return_value = pendulum.from_timestamp(1578487013)
|
||||
c = TimestampCompleter()
|
||||
c = TimestampCompleter(is_milliseconds=True, future_time=False)
|
||||
|
||||
fake_document = MagicMock()
|
||||
fake_document.text = fake_document.text_before_cursor = "30"
|
||||
|
@ -260,8 +260,87 @@ def test_timestamp_completer_humanize_time_completion(fake_now):
|
|||
]
|
||||
|
||||
|
||||
@patch("iredis.completers.pendulum.now")
|
||||
def test_timestamp_completer_humanize_time_completion_seconds(fake_now):
|
||||
fake_now.return_value = pendulum.from_timestamp(1578487013)
|
||||
c = TimestampCompleter(is_milliseconds=False, future_time=False)
|
||||
|
||||
fake_document = MagicMock()
|
||||
fake_document.text = fake_document.text_before_cursor = "30"
|
||||
completions = list(c.get_completions(fake_document, None))
|
||||
|
||||
assert completions == [
|
||||
Completion(
|
||||
text="1575895013",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1575895013")]),
|
||||
display_meta="30 days ago (2019-12-09 12:36:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1578379013",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578379013")]),
|
||||
display_meta="30 hours ago (2020-01-07 06:36:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1578485213",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578485213")]),
|
||||
display_meta="30 minutes ago (2020-01-08 12:06:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1578486983",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578486983")]),
|
||||
display_meta="30 seconds ago (2020-01-08 12:36:23)",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@patch("iredis.completers.pendulum.now")
|
||||
def test_timestamp_completer_humanize_time_completion_seconds_future_time(fake_now):
|
||||
fake_now.return_value = pendulum.from_timestamp(1578487013)
|
||||
c = TimestampCompleter(is_milliseconds=False, future_time=True)
|
||||
|
||||
fake_document = MagicMock()
|
||||
fake_document.text = fake_document.text_before_cursor = "30"
|
||||
completions = list(c.get_completions(fake_document, None))
|
||||
|
||||
print(completions)
|
||||
for c in completions:
|
||||
print(c.text)
|
||||
print(c.display)
|
||||
print(c.display_meta)
|
||||
assert completions == [
|
||||
Completion(
|
||||
text="1578487043",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578487043")]),
|
||||
display_meta="30 seconds later (2020-01-08 12:37:23)",
|
||||
),
|
||||
Completion(
|
||||
text="1578488813",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578488813")]),
|
||||
display_meta="30 minutes later (2020-01-08 13:06:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1578595013",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1578595013")]),
|
||||
display_meta="30 hours later (2020-01-09 18:36:53)",
|
||||
),
|
||||
Completion(
|
||||
text="1581079013",
|
||||
start_position=-2,
|
||||
display=FormattedText([("", "1581079013")]),
|
||||
display_meta="30 days later (2020-02-07 12:36:53)",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def test_timestamp_completer_datetime_format_time_completion():
|
||||
c = TimestampCompleter()
|
||||
c = TimestampCompleter(is_milliseconds=True, future_time=False)
|
||||
fake_document = MagicMock()
|
||||
fake_document.text = fake_document.text_before_cursor = "2020-02-07"
|
||||
completions = list(c.get_completions(fake_document, None))
|
||||
|
@ -299,14 +378,18 @@ def test_completion_casing():
|
|||
completion.text for completion in c.get_completions(fake_document, None)
|
||||
] == [
|
||||
"get",
|
||||
"getex",
|
||||
"getset",
|
||||
"getdel",
|
||||
"getbit",
|
||||
"geopos",
|
||||
"geoadd",
|
||||
"geohash",
|
||||
"geodist",
|
||||
"getrange",
|
||||
"geosearch",
|
||||
"georadius",
|
||||
"geosearchstore",
|
||||
"georadiusbymember",
|
||||
]
|
||||
|
||||
|
@ -314,19 +397,19 @@ def test_completion_casing():
|
|||
fake_document.text = fake_document.text_before_cursor = "GET"
|
||||
assert [
|
||||
completion.text for completion in c.get_completions(fake_document, None)
|
||||
] == ["GET", "GETSET", "GETBIT", "GETRANGE"]
|
||||
] == ["GET", "GETEX", "GETSET", "GETDEL", "GETBIT", "GETRANGE"]
|
||||
|
||||
c = IRedisCompleter(completion_casing="upper")
|
||||
fake_document.text = fake_document.text_before_cursor = "get"
|
||||
assert [
|
||||
completion.text for completion in c.get_completions(fake_document, None)
|
||||
] == ["GET", "GETSET", "GETBIT", "GETRANGE"]
|
||||
] == ["GET", "GETEX", "GETSET", "GETDEL", "GETBIT", "GETRANGE"]
|
||||
|
||||
c = IRedisCompleter(completion_casing="lower")
|
||||
fake_document.text = fake_document.text_before_cursor = "GET"
|
||||
assert [
|
||||
completion.text for completion in c.get_completions(fake_document, None)
|
||||
] == ["get", "getset", "getbit", "getrange"]
|
||||
] == ["get", "getex", "getset", "getdel", "getbit", "getrange"]
|
||||
|
||||
|
||||
def test_username_completer():
|
||||
|
|
Loading…
Add table
Reference in a new issue