diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 9ef25fa3..57d86963 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.14.0 +current_version = 1.14.1 commit = True tag = True diff --git a/CHANGELOG.md b/CHANGELOG.md index c98e9f2c..7ee0f7de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## UPCOMING +### 1.14.1 + +- Bugfix: fix argument parsing, `"foo\nbar"` will be parsed to `foo` and `\` + and `n` and `bar`, the `\` and `n` should be one character `\n` instead. + ## 1.14 - Dependency: upgrade redis-py to 5 (thanks to [chayim]) diff --git a/iredis/__init__.py b/iredis/__init__.py index b9f68edb..4454c8d4 100644 --- a/iredis/__init__.py +++ b/iredis/__init__.py @@ -1 +1 @@ -__version__ = "1.14.0" +__version__ = "1.14.1" diff --git a/iredis/client.py b/iredis/client.py index f7164b89..a9526385 100644 --- a/iredis/client.py +++ b/iredis/client.py @@ -1,6 +1,7 @@ """ IRedis client. """ + import re import os import sys diff --git a/iredis/commands.py b/iredis/commands.py index cf21a545..3580cdbe 100644 --- a/iredis/commands.py +++ b/iredis/commands.py @@ -120,7 +120,7 @@ def split_command_args(command): # `command` with `args` is ('in') which is an invalid case. normalized_input_command = " ".join(command.split()).upper() if ( - re.search("\s", command) + re.search(r"\s", command) and command_name.startswith(normalized_input_command) and command_name != normalized_input_command ): diff --git a/iredis/completers.py b/iredis/completers.py index 6f9ecac3..b17d3cc5 100644 --- a/iredis/completers.py +++ b/iredis/completers.py @@ -139,8 +139,7 @@ def get_completions( ) # here we yield bigger timestamp first. - for completion in sorted(completions, key=lambda a: a.text): - yield completion + yield from sorted(completions, key=lambda a: a.text) class IRedisCompleter(Completer): @@ -290,7 +289,7 @@ def _touch_keys(self, items): self.key_completer.touch_words(ensure_str(items)) def __repr__(self) -> str: - return "DynamicCompleter(%r -> %r)" % ( + return "DynamicCompleter({!r} -> {!r})".format( self.get_completer, self.current_completer, ) diff --git a/iredis/config.py b/iredis/config.py index 4041bb65..7a542208 100644 --- a/iredis/config.py +++ b/iredis/config.py @@ -88,13 +88,13 @@ def read_config_file(f): config = ConfigObj(f, interpolation=False, encoding="utf8") except ConfigObjError as e: logger.error( - "Unable to parse line {0} of config file " "'{1}'.".format(e.line_number, f) + "Unable to parse line {} of config file " "'{}'.".format(e.line_number, f) ) logger.error("Using successfully parsed config values.") return e.config - except (IOError, OSError) as e: + except OSError as e: logger.error( - "You don't have permission to read " "config file '{0}'.".format(e.filename) + "You don't have permission to read " "config file '{}'.".format(e.filename) ) return None diff --git a/iredis/entry.py b/iredis/entry.py index 0799a078..b4615bba 100644 --- a/iredis/entry.py +++ b/iredis/entry.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import os import logging import sys diff --git a/iredis/markdown.py b/iredis/markdown.py index 89297ec0..a24b7931 100644 --- a/iredis/markdown.py +++ b/iredis/markdown.py @@ -39,7 +39,7 @@ def list(self, body, ordered, *args, **kwargs): tag = "ul" if ordered: tag = "ol" - return "<%s>%s\n" % (tag, body, tag) + return "<{}>{}\n".format(tag, body, tag) def list_item(self, text, *args): """Rendering list item snippet. Like ``
  • ``.""" @@ -62,5 +62,5 @@ def replace_to_markdown_title(original): def render(text): replaced = replace_to_markdown_title(text) html_text = markdown_render(replaced) - logger.debug("[Document] {} ...".format(html_text)[:20]) + logger.debug(f"[Document] {html_text} ..."[:20]) return to_formatted_text(HTML(html_text)) diff --git a/iredis/renders.py b/iredis/renders.py index d695407e..94582635 100644 --- a/iredis/renders.py +++ b/iredis/renders.py @@ -4,6 +4,7 @@ func(redis-response) -> formatted result(str) """ + import logging import time from packaging.version import parse as version_parse diff --git a/iredis/utils.py b/iredis/utils.py index 5a614258..aa005338 100644 --- a/iredis/utils.py +++ b/iredis/utils.py @@ -39,10 +39,11 @@ def literal_bytes(b): return b -def _valid_token(words): - token = "".join(words).strip() - if token: - yield token +def nappend(word, c, pre_back_slash): + if pre_back_slash and c == "n": # \n + word[-1] = "\n" + else: + word.append(c) def strip_quote_args(s): @@ -69,7 +70,7 @@ def strip_quote_args(s): # previous char is \ , merge with current " word[-1] = char else: - word.append(char) + nappend(word, char, pre_back_slash) # not in quote else: # separator @@ -81,7 +82,7 @@ def strip_quote_args(s): elif char in ["'", '"']: in_quote = char else: - word.append(char) + nappend(word, char, pre_back_slash) if char == "\\" and not pre_back_slash: pre_back_slash = True else: diff --git a/iredis/warning.py b/iredis/warning.py index bb8231ee..0217a297 100644 --- a/iredis/warning.py +++ b/iredis/warning.py @@ -1,7 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - - import sys import click from .commands import dangerous_commands diff --git a/poetry.lock b/poetry.lock index c0742b58..1edd2b63 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "async-timeout" @@ -80,13 +80,13 @@ six = "*" [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.1.3" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, ] [package.extras] @@ -94,13 +94,13 @@ test = ["pytest (>=6)"] [[package]] name = "importlib-resources" -version = "6.1.1" +version = "6.4.0" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, - {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, ] [package.dependencies] @@ -108,7 +108,7 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] +testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -246,13 +246,13 @@ test = ["time-machine (>=2.6.0)"] [[package]] name = "pexpect" -version = "4.9.0" +version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" files = [ - {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, - {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, ] [package.dependencies] @@ -260,13 +260,13 @@ ptyprocess = ">=0.5" [[package]] name = "pluggy" -version = "1.3.0" +version = "1.2.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, ] [package.extras] @@ -275,13 +275,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "prompt-toolkit" -version = "3.0.43" +version = "3.0.39" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, - {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, + {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, + {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, ] [package.dependencies] @@ -300,18 +300,17 @@ files = [ [[package]] name = "pygments" -version = "2.17.2" +version = "2.16.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, ] [package.extras] plugins = ["importlib-metadata"] -windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" @@ -391,13 +390,13 @@ files = [ [[package]] name = "tzdata" -version = "2023.3" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] @@ -413,18 +412,18 @@ files = [ [[package]] name = "zipp" -version = "3.17.0" +version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" diff --git a/pyproject.toml b/pyproject.toml index c041976e..55b76837 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "iredis" -version = "1.14.0" +version = "1.14.1" description = "Terminal client for Redis with auto-completion and syntax highlighting." authors = ["laixintao "] readme = 'README.md' diff --git a/tests/cli_tests/test_config.py b/tests/cli_tests/test_config.py index 1795c624..eeaba333 100644 --- a/tests/cli_tests/test_config.py +++ b/tests/cli_tests/test_config.py @@ -19,7 +19,7 @@ def test_log_location_config(): log = Path("/tmp/iredis1.log") assert log.exists() - with open(log, "r") as logfile: + with open(log) as logfile: content = logfile.read() assert len(content) > 100 diff --git a/tests/cli_tests/test_history.py b/tests/cli_tests/test_history.py index 09e6c829..acb25d3d 100644 --- a/tests/cli_tests/test_history.py +++ b/tests/cli_tests/test_history.py @@ -10,7 +10,7 @@ def test_history_not_log_auth(cli): cli.sendline("set foo bar") cli.expect("OK") - with open(os.path.expanduser("~/.iredis_history"), "r") as history_file: + with open(os.path.expanduser("~/.iredis_history")) as history_file: content = history_file.read() assert "set foo bar" in content @@ -36,7 +36,7 @@ def test_history_create_and_writing_with_config(): log = Path("/tmp/iredis_history.txt") assert log.exists() - with open(log, "r") as logfile: + with open(log) as logfile: content = logfile.read() assert "set hello world" in content diff --git a/tests/cli_tests/test_pager.py b/tests/cli_tests/test_pager.py index c3f9fb05..e8106a4f 100644 --- a/tests/cli_tests/test_pager.py +++ b/tests/cli_tests/test_pager.py @@ -13,12 +13,12 @@ TEST_PAGER_BOUNDARY = "---boundary---" TEST_PAGER_BOUNDARY_NUMBER = "---88938347271---" -env_pager = "{0} {1} {2}".format( +env_pager = "{} {} {}".format( sys.executable, os.path.join(pathlib.Path(__file__).parent, "wrappager.py"), TEST_PAGER_BOUNDARY, ) -env_pager_numbers = "{0} {1} {2}".format( +env_pager_numbers = "{} {} {}".format( sys.executable, os.path.join(pathlib.Path(__file__).parent, "wrappager.py"), TEST_PAGER_BOUNDARY_NUMBER, diff --git a/tests/conftest.py b/tests/conftest.py index 593e8a88..42840e33 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -53,7 +53,7 @@ def judge_command_func(input_text, expect): return variables = m.variables() - print("Found variables: {}".format(variables)) + print(f"Found variables: {variables}") for expect_token, expect_value in expect.items(): all_variables = variables.getall(expect_token) if len(all_variables) > 1: diff --git a/tests/unittests/test_entry.py b/tests/unittests/test_entry.py index e53861e6..99d69312 100644 --- a/tests/unittests/test_entry.py +++ b/tests/unittests/test_entry.py @@ -174,6 +174,19 @@ def test_command_shell_options_higher_priority(): verify_ssl=None, ), ), + ( + "redis://username:pass@word@localhost:12345/2", + DSN( + scheme="redis", + host="localhost", + port=12345, + path=None, + db=2, + username="username", + password="pass@word", + verify_ssl=None, + ), + ), ( "redis://username@localhost:12345", DSN( diff --git a/tests/unittests/test_utils.py b/tests/unittests/test_utils.py index 98ea8db2..e00eafff 100644 --- a/tests/unittests/test_utils.py +++ b/tests/unittests/test_utils.py @@ -55,6 +55,7 @@ def test_timer(): (r'""', [""]), # set foo "" is a legal command (r"\\", ["\\\\"]), # backslash are legal ("\\hello\\", ["\\hello\\"]), # backslash are legal + ('foo "bar\\n1"', ["foo", "bar\n1"]), ], ) def test_stripe_quote_escape_in_quote(test_input, expected):