Adding upstream version 1.31.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
9aaa9c7fe0
commit
5829a372a2
23 changed files with 166 additions and 107 deletions
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
@ -15,13 +15,13 @@ jobs:
|
|||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: astral-sh/setup-uv@v1
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
with:
|
||||
version: "latest"
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
|
|
11
.github/workflows/lint.yml
vendored
11
.github/workflows/lint.yml
vendored
|
@ -15,16 +15,15 @@ jobs:
|
|||
- name: Check out Git repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
# todo
|
||||
# remember to sync the ruff-check version number with pyproject.toml
|
||||
# - name: Run ruff check
|
||||
# uses: astral-sh/ruff-action@9828f49eb4cadf267b40eaa330295c412c68c1f9 # v3.2.2
|
||||
# with:
|
||||
# version: 0.11.5
|
||||
- name: Run ruff check
|
||||
uses: astral-sh/ruff-action@c6bea5606c33b5d04902374392d9233464b90660 # v3.3.0
|
||||
with:
|
||||
version: 0.11.5
|
||||
|
||||
# remember to sync the ruff-check version number with pyproject.toml
|
||||
- name: Run ruff format
|
||||
uses: astral-sh/ruff-action@9828f49eb4cadf267b40eaa330295c412c68c1f9 # v3.2.2
|
||||
uses: astral-sh/ruff-action@c6bea5606c33b5d04902374392d9233464b90660 # v3.3.0
|
||||
with:
|
||||
version: 0.11.5
|
||||
args: 'format --check'
|
||||
|
|
25
.github/workflows/publish.yml
vendored
25
.github/workflows/publish.yml
vendored
|
@ -16,13 +16,13 @@ jobs:
|
|||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: astral-sh/setup-uv@v1
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
with:
|
||||
version: "latest"
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
|
@ -46,23 +46,22 @@ jobs:
|
|||
run: |
|
||||
uv run tox -e py${{ matrix.python-version }}
|
||||
|
||||
# TODO enable style checks here and in CI for PRs
|
||||
#
|
||||
# - name: Run Style Checks
|
||||
# run: uv run tox -e style
|
||||
# arguably this should be made identical to CI for PRs
|
||||
- name: Run Style Checks
|
||||
run: uv run tox -e style
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: astral-sh/setup-uv@v1
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
with:
|
||||
version: "latest"
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version: '3.13'
|
||||
|
||||
|
@ -73,7 +72,7 @@ jobs:
|
|||
run: uv build
|
||||
|
||||
- name: Store the distribution packages
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: python-packages
|
||||
path: dist/
|
||||
|
@ -88,9 +87,9 @@ jobs:
|
|||
id-token: write
|
||||
steps:
|
||||
- name: Download distribution packages
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: python-packages
|
||||
path: dist/
|
||||
- name: Publish to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
|
||||
|
|
18
changelog.md
18
changelog.md
|
@ -1,3 +1,21 @@
|
|||
1.31.2 (2025/05/01)
|
||||
===================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
* Let table-name extraction work on multi-statement inputs.
|
||||
|
||||
|
||||
Internal
|
||||
--------
|
||||
|
||||
* Work on passing `ruff check` linting.
|
||||
* Remove backward-compatibility hacks.
|
||||
* Pin more GitHub Actions and add Dependabot support.
|
||||
* Enable xpassing test.
|
||||
|
||||
|
||||
1.31.1 (2025/04/25)
|
||||
===================
|
||||
|
||||
|
|
|
@ -35,11 +35,13 @@ def _multiline_exception(text):
|
|||
text.lower().startswith("delimiter")
|
||||
or
|
||||
# Ended with the current delimiter (usually a semi-column)
|
||||
text.endswith(special.get_current_delimiter())
|
||||
or text.endswith("\\g")
|
||||
or text.endswith("\\G")
|
||||
or text.endswith(r"\e")
|
||||
or text.endswith(r"\clip")
|
||||
text.endswith((
|
||||
special.get_current_delimiter(),
|
||||
"\\g",
|
||||
"\\G",
|
||||
r"\e",
|
||||
r"\clip",
|
||||
))
|
||||
or
|
||||
# Exit doesn't need semi-column`
|
||||
(text == "exit")
|
||||
|
|
|
@ -11,11 +11,6 @@ from typing import Union, IO
|
|||
from configobj import ConfigObj, ConfigObjError
|
||||
import pyaes
|
||||
|
||||
try:
|
||||
basestring
|
||||
except NameError:
|
||||
basestring = str
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -40,7 +35,7 @@ def read_config_file(f, list_values=True):
|
|||
|
||||
"""
|
||||
|
||||
if isinstance(f, basestring):
|
||||
if isinstance(f, str):
|
||||
f = os.path.expanduser(f)
|
||||
|
||||
try:
|
||||
|
@ -73,7 +68,7 @@ def get_included_configs(config_file: Union[str, TextIOWrapper]) -> list:
|
|||
try:
|
||||
with open(config_file) as f:
|
||||
include_directives = filter(lambda s: s.startswith("!includedir"), f)
|
||||
dirs_split = map(lambda s: s.strip().split()[-1], include_directives)
|
||||
dirs_split = (s.strip().split()[-1] for s in include_directives)
|
||||
dirs = filter(os.path.isdir, dirs_split)
|
||||
for dir_ in dirs:
|
||||
for filename in os.listdir(dir_):
|
||||
|
@ -284,7 +279,7 @@ def str_to_bool(s):
|
|||
"""Convert a string value to its corresponding boolean value."""
|
||||
if isinstance(s, bool):
|
||||
return s
|
||||
elif not isinstance(s, basestring):
|
||||
elif not isinstance(s, str):
|
||||
raise TypeError("argument must be a string")
|
||||
|
||||
true_values = ("true", "on", "1")
|
||||
|
@ -305,7 +300,7 @@ def strip_matching_quotes(s):
|
|||
values.
|
||||
|
||||
"""
|
||||
if isinstance(s, basestring) and len(s) >= 2 and s[0] == s[-1] and s[0] in ('"', "'"):
|
||||
if isinstance(s, str) and len(s) >= 2 and s[0] == s[-1] and s[0] in ('"', "'"):
|
||||
s = s[1:-1]
|
||||
return s
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from collections import defaultdict
|
||||
from io import open
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
|
@ -7,11 +6,8 @@ import traceback
|
|||
import logging
|
||||
import threading
|
||||
import re
|
||||
import stat
|
||||
from collections import namedtuple
|
||||
|
||||
from pygments.lexer import combined
|
||||
|
||||
try:
|
||||
from pwd import getpwuid
|
||||
except ImportError:
|
||||
|
@ -62,18 +58,10 @@ import itertools
|
|||
|
||||
click.disable_unicode_literals_warning = True
|
||||
|
||||
try:
|
||||
from urlparse import urlparse
|
||||
from urlparse import unquote
|
||||
except ImportError:
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import unquote
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import unquote
|
||||
|
||||
try:
|
||||
import importlib.resources as resources
|
||||
except ImportError:
|
||||
# Python < 3.7
|
||||
import importlib_resources as resources
|
||||
from importlib import resources
|
||||
|
||||
try:
|
||||
import paramiko
|
||||
|
@ -89,8 +77,6 @@ SUPPORT_INFO = "Home: http://mycli.net\nBug tracker: https://github.com/dbcli/my
|
|||
class PasswordFileError(Exception):
|
||||
"""Base exception for errors related to reading password files."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class MyCli(object):
|
||||
default_prompt = "\\t \\u@\\h:\\d> "
|
||||
|
@ -1458,7 +1444,7 @@ def is_mutating(status):
|
|||
if not status:
|
||||
return False
|
||||
|
||||
mutating = set(["insert", "update", "delete", "alter", "create", "drop", "replace", "truncate", "load", "rename"])
|
||||
mutating = {"insert", "update", "delete", "alter", "create", "drop", "replace", "truncate", "load", "rename"}
|
||||
return status.split(None, 1)[0].lower() in mutating
|
||||
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ def suggest_based_on_last_token(token, text_before_cursor, full_text, identifier
|
|||
else:
|
||||
token_v = token.value.lower()
|
||||
|
||||
is_operand = lambda x: x and any([x.endswith(op) for op in ["+", "-", "*", "/"]]) # noqa: E731
|
||||
is_operand = lambda x: x and any(x.endswith(op) for op in ["+", "-", "*", "/"]) # noqa: E731
|
||||
|
||||
if not token:
|
||||
return [{"type": "keyword"}, {"type": "special"}]
|
||||
|
@ -289,5 +289,5 @@ def suggest_based_on_last_token(token, text_before_cursor, full_text, identifier
|
|||
return [{"type": "keyword"}]
|
||||
|
||||
|
||||
def identifies(id, schema, table, alias):
|
||||
return id == alias or id == table or (schema and (id == schema + "." + table))
|
||||
def identifies(identifier, schema, table, alias):
|
||||
return identifier == alias or identifier == table or (schema and (identifier == schema + "." + table))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import re
|
||||
import sqlglot
|
||||
import sqlparse
|
||||
from sqlparse.sql import IdentifierList, Identifier, Function
|
||||
from sqlparse.tokens import Keyword, DML, Punctuation
|
||||
|
@ -166,6 +167,42 @@ def extract_tables(sql):
|
|||
return list(extract_table_identifiers(stream))
|
||||
|
||||
|
||||
def extract_tables_from_complete_statements(sql):
|
||||
"""Extract the table names from a complete and valid series of SQL
|
||||
statements.
|
||||
|
||||
Returns a list of (schema, table, alias) tuples
|
||||
|
||||
"""
|
||||
# sqlglot chokes entirely on things like "\T" that it doesn't know about,
|
||||
# but is much better at extracting table names from complete statements.
|
||||
# sqlparse can extract the series of statements, though it also doesn't
|
||||
# understand "\T".
|
||||
roughly_parsed = sqlparse.parse(sql)
|
||||
if not roughly_parsed:
|
||||
return []
|
||||
|
||||
finely_parsed = []
|
||||
for statement in roughly_parsed:
|
||||
try:
|
||||
finely_parsed.append(sqlglot.parse_one(str(statement), read='mysql'))
|
||||
except sqlglot.errors.ParseError:
|
||||
pass
|
||||
|
||||
tables = []
|
||||
for statement in finely_parsed:
|
||||
for identifier in statement.find_all(sqlglot.exp.Table):
|
||||
if identifier.parent_select.sql().startswith('WITH'):
|
||||
continue
|
||||
tables.append((
|
||||
None if identifier.db == '' else identifier.db,
|
||||
identifier.name,
|
||||
None if identifier.alias == '' else identifier.alias,
|
||||
))
|
||||
|
||||
return tables
|
||||
|
||||
|
||||
def find_prev_keyword(sql):
|
||||
"""Find the last sql keyword in an SQL statement
|
||||
|
||||
|
|
|
@ -26,10 +26,10 @@ class DelimiterCommand(object):
|
|||
|
||||
return [stmt.replace(";", self._delimiter).replace(placeholder, ";") for stmt in split]
|
||||
|
||||
def queries_iter(self, input):
|
||||
def queries_iter(self, input_str):
|
||||
"""Iterate over queries in the input string."""
|
||||
|
||||
queries = self._split(input)
|
||||
queries = self._split(input_str)
|
||||
while queries:
|
||||
for sql in queries:
|
||||
delimiter = self._delimiter
|
||||
|
|
|
@ -4,7 +4,6 @@ import locale
|
|||
import logging
|
||||
import subprocess
|
||||
import shlex
|
||||
from io import open
|
||||
from time import sleep
|
||||
|
||||
import click
|
||||
|
@ -547,6 +546,6 @@ def get_current_delimiter():
|
|||
|
||||
|
||||
@export
|
||||
def split_queries(input):
|
||||
for query in delimiter_command.queries_iter(input):
|
||||
def split_queries(input_str):
|
||||
for query in delimiter_command.queries_iter(input_str):
|
||||
yield query
|
||||
|
|
|
@ -108,7 +108,7 @@ def show_keyword_help(cur, arg):
|
|||
|
||||
@special_command("exit", "\\q", "Exit.", arg_type=NO_QUERY, aliases=("\\q",))
|
||||
@special_command("quit", "\\q", "Quit.", arg_type=NO_QUERY)
|
||||
def quit(*_args):
|
||||
def quit_(*_args):
|
||||
raise EOFError
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Format adapter for sql."""
|
||||
|
||||
from mycli.packages.parseutils import extract_tables
|
||||
from mycli.packages.parseutils import extract_tables_from_complete_statements
|
||||
|
||||
supported_formats = (
|
||||
"sql-insert",
|
||||
|
@ -20,7 +20,7 @@ def escape_for_sql_statement(value):
|
|||
|
||||
|
||||
def adapter(data, headers, table_format=None, **kwargs):
|
||||
tables = extract_tables(formatter.query)
|
||||
tables = extract_tables_from_complete_statements(formatter.query)
|
||||
if len(tables) > 0:
|
||||
table = tables[0]
|
||||
if table[0]:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import logging
|
||||
from re import compile, escape
|
||||
import re
|
||||
from collections import Counter
|
||||
|
||||
from prompt_toolkit.completion import Completer, Completion
|
||||
|
@ -900,7 +900,7 @@ class SQLCompleter(Completer):
|
|||
self.reserved_words = set()
|
||||
for x in self.keywords:
|
||||
self.reserved_words.update(x.split())
|
||||
self.name_pattern = compile(r"^[_a-z][_a-z0-9\$]*$")
|
||||
self.name_pattern = re.compile(r"^[_a-z][_a-z0-9\$]*$")
|
||||
|
||||
self.special_commands = []
|
||||
self.table_formats = supported_formats
|
||||
|
@ -1075,8 +1075,8 @@ class SQLCompleter(Completer):
|
|||
completions = []
|
||||
|
||||
if fuzzy:
|
||||
regex = ".*?".join(map(escape, text))
|
||||
pat = compile("(%s)" % regex)
|
||||
regex = ".*?".join(map(re.escape, text))
|
||||
pat = re.compile("(%s)" % regex)
|
||||
for item in collection:
|
||||
r = pat.search(item.lower())
|
||||
if r:
|
||||
|
|
|
@ -62,7 +62,7 @@ line-length = 140
|
|||
[tool.ruff.lint]
|
||||
select = [
|
||||
'A',
|
||||
'I',
|
||||
# 'I', # todo enableme imports
|
||||
'E',
|
||||
'W',
|
||||
'F',
|
||||
|
@ -79,12 +79,16 @@ ignore = [
|
|||
'E114', # indentation-with-invalid-multiple-comment
|
||||
'E117', # over-indented
|
||||
'W191', # tab-indentation
|
||||
# TODO
|
||||
'PIE796', # todo enableme Enum contains duplicate value
|
||||
]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
force-sort-within-sections = true
|
||||
known-first-party = [
|
||||
'mycli',
|
||||
'test',
|
||||
'steps',
|
||||
]
|
||||
|
||||
[tool.ruff.format]
|
||||
|
|
|
@ -28,7 +28,7 @@ def test_select_keyword_completion(completer, complete_event):
|
|||
text = "SEL"
|
||||
position = len("SEL")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([Completion(text="SELECT", start_position=-3)])
|
||||
assert result == [Completion(text="SELECT", start_position=-3)]
|
||||
|
||||
|
||||
def test_function_name_completion(completer, complete_event):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import pytest
|
||||
from mycli.packages.parseutils import (
|
||||
extract_tables,
|
||||
extract_tables_from_complete_statements,
|
||||
query_starts_with,
|
||||
queries_start_with,
|
||||
is_destructive,
|
||||
|
@ -77,7 +78,6 @@ def test_simple_insert_single_table():
|
|||
assert tables == [(None, "abc", "abc")]
|
||||
|
||||
|
||||
@pytest.mark.xfail
|
||||
def test_simple_insert_single_table_schema_qualified():
|
||||
tables = extract_tables('insert into abc.def (id, name) values (1, "def")')
|
||||
assert tables == [("abc", "def", None)]
|
||||
|
@ -108,6 +108,22 @@ def test_join_as_table():
|
|||
assert tables == [(None, "my_table", "m")]
|
||||
|
||||
|
||||
def test_extract_tables_from_complete_statements():
|
||||
tables = extract_tables_from_complete_statements("SELECT * FROM my_table AS m WHERE m.a > 5")
|
||||
assert tables == [(None, "my_table", "m")]
|
||||
|
||||
|
||||
def test_extract_tables_from_complete_statements_cte():
|
||||
tables = extract_tables_from_complete_statements("WITH my_cte (id, num) AS ( SELECT id, COUNT(1) FROM my_table GROUP BY id ) SELECT *")
|
||||
assert tables == [(None, "my_table", None)]
|
||||
|
||||
|
||||
# this would confuse plain extract_tables() per #1122
|
||||
def test_extract_tables_from_multiple_complete_statements():
|
||||
tables = extract_tables_from_complete_statements(r'\T sql-insert; SELECT * FROM my_table AS m WHERE m.a > 5')
|
||||
assert tables == [(None, "my_table", "m")]
|
||||
|
||||
|
||||
def test_query_starts_with():
|
||||
query = "USE test;"
|
||||
assert query_starts_with(query, ("use",)) is True
|
||||
|
|
|
@ -58,7 +58,7 @@ def test_select_keyword_completion(completer, complete_event):
|
|||
text = "SEL"
|
||||
position = len("SEL")
|
||||
result = completer.get_completions(Document(text=text, cursor_position=position), complete_event)
|
||||
assert list(result) == list([Completion(text="SELECT", start_position=-3)])
|
||||
assert list(result) == [Completion(text="SELECT", start_position=-3)]
|
||||
|
||||
|
||||
def test_select_star(completer, complete_event):
|
||||
|
@ -72,19 +72,19 @@ def test_table_completion(completer, complete_event):
|
|||
text = "SELECT * FROM "
|
||||
position = len(text)
|
||||
result = completer.get_completions(Document(text=text, cursor_position=position), complete_event)
|
||||
assert list(result) == list([
|
||||
assert list(result) == [
|
||||
Completion(text="users", start_position=0),
|
||||
Completion(text="orders", start_position=0),
|
||||
Completion(text="`select`", start_position=0),
|
||||
Completion(text="`réveillé`", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_function_name_completion(completer, complete_event):
|
||||
text = "SELECT MA"
|
||||
position = len("SELECT MA")
|
||||
result = completer.get_completions(Document(text=text, cursor_position=position), complete_event)
|
||||
assert list(result) == list([
|
||||
assert list(result) == [
|
||||
Completion(text="MAX", start_position=-2),
|
||||
Completion(text="CHANGE MASTER TO", start_position=-2),
|
||||
Completion(text="CURRENT_TIMESTAMP", start_position=-2),
|
||||
|
@ -94,7 +94,7 @@ def test_function_name_completion(completer, complete_event):
|
|||
Completion(text="PRIMARY", start_position=-2),
|
||||
Completion(text="ROW_FORMAT", start_position=-2),
|
||||
Completion(text="SMALLINT", start_position=-2),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_suggested_column_names(completer, complete_event):
|
||||
|
@ -134,13 +134,13 @@ def test_suggested_column_names_in_function(completer, complete_event):
|
|||
text = "SELECT MAX( from users"
|
||||
position = len("SELECT MAX(")
|
||||
result = completer.get_completions(Document(text=text, cursor_position=position), complete_event)
|
||||
assert list(result) == list([
|
||||
assert list(result) == [
|
||||
Completion(text="*", start_position=0),
|
||||
Completion(text="id", start_position=0),
|
||||
Completion(text="email", start_position=0),
|
||||
Completion(text="first_name", start_position=0),
|
||||
Completion(text="last_name", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_suggested_column_names_with_table_dot(completer, complete_event):
|
||||
|
@ -154,13 +154,13 @@ def test_suggested_column_names_with_table_dot(completer, complete_event):
|
|||
text = "SELECT users. from users"
|
||||
position = len("SELECT users.")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([
|
||||
assert result == [
|
||||
Completion(text="*", start_position=0),
|
||||
Completion(text="id", start_position=0),
|
||||
Completion(text="email", start_position=0),
|
||||
Completion(text="first_name", start_position=0),
|
||||
Completion(text="last_name", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_suggested_column_names_with_alias(completer, complete_event):
|
||||
|
@ -174,13 +174,13 @@ def test_suggested_column_names_with_alias(completer, complete_event):
|
|||
text = "SELECT u. from users u"
|
||||
position = len("SELECT u.")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([
|
||||
assert result == [
|
||||
Completion(text="*", start_position=0),
|
||||
Completion(text="id", start_position=0),
|
||||
Completion(text="email", start_position=0),
|
||||
Completion(text="first_name", start_position=0),
|
||||
Completion(text="last_name", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_suggested_multiple_column_names(completer, complete_event):
|
||||
|
@ -221,13 +221,13 @@ def test_suggested_multiple_column_names_with_alias(completer, complete_event):
|
|||
text = "SELECT u.id, u. from users u"
|
||||
position = len("SELECT u.id, u.")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([
|
||||
assert result == [
|
||||
Completion(text="*", start_position=0),
|
||||
Completion(text="id", start_position=0),
|
||||
Completion(text="email", start_position=0),
|
||||
Completion(text="first_name", start_position=0),
|
||||
Completion(text="last_name", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_suggested_multiple_column_names_with_dot(completer, complete_event):
|
||||
|
@ -242,65 +242,65 @@ def test_suggested_multiple_column_names_with_dot(completer, complete_event):
|
|||
text = "SELECT users.id, users. from users u"
|
||||
position = len("SELECT users.id, users.")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([
|
||||
assert result == [
|
||||
Completion(text="*", start_position=0),
|
||||
Completion(text="id", start_position=0),
|
||||
Completion(text="email", start_position=0),
|
||||
Completion(text="first_name", start_position=0),
|
||||
Completion(text="last_name", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_suggested_aliases_after_on(completer, complete_event):
|
||||
text = "SELECT u.name, o.id FROM users u JOIN orders o ON "
|
||||
position = len("SELECT u.name, o.id FROM users u JOIN orders o ON ")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([
|
||||
assert result == [
|
||||
Completion(text="u", start_position=0),
|
||||
Completion(text="o", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_suggested_aliases_after_on_right_side(completer, complete_event):
|
||||
text = "SELECT u.name, o.id FROM users u JOIN orders o ON o.user_id = "
|
||||
position = len("SELECT u.name, o.id FROM users u JOIN orders o ON o.user_id = ")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([
|
||||
assert result == [
|
||||
Completion(text="u", start_position=0),
|
||||
Completion(text="o", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_suggested_tables_after_on(completer, complete_event):
|
||||
text = "SELECT users.name, orders.id FROM users JOIN orders ON "
|
||||
position = len("SELECT users.name, orders.id FROM users JOIN orders ON ")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([
|
||||
assert result == [
|
||||
Completion(text="users", start_position=0),
|
||||
Completion(text="orders", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_suggested_tables_after_on_right_side(completer, complete_event):
|
||||
text = "SELECT users.name, orders.id FROM users JOIN orders ON orders.user_id = "
|
||||
position = len("SELECT users.name, orders.id FROM users JOIN orders ON orders.user_id = ")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([
|
||||
assert result == [
|
||||
Completion(text="users", start_position=0),
|
||||
Completion(text="orders", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_table_names_after_from(completer, complete_event):
|
||||
text = "SELECT * FROM "
|
||||
position = len("SELECT * FROM ")
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
assert result == list([
|
||||
assert result == [
|
||||
Completion(text="users", start_position=0),
|
||||
Completion(text="orders", start_position=0),
|
||||
Completion(text="`select`", start_position=0),
|
||||
Completion(text="`réveillé`", start_position=0),
|
||||
])
|
||||
]
|
||||
|
||||
|
||||
def test_auto_escaped_col_names(completer, complete_event):
|
||||
|
@ -369,5 +369,5 @@ def dummy_list_path(dir_name):
|
|||
def test_file_name_completion(completer, complete_event, text, expected):
|
||||
position = len(text)
|
||||
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
|
||||
expected = list((Completion(txt, pos) for txt, pos in expected))
|
||||
expected = [Completion(txt, pos) for txt, pos in expected]
|
||||
assert result == expected
|
||||
|
|
|
@ -223,9 +223,7 @@ def test_watch_query_full():
|
|||
expected_results = 4
|
||||
ctrl_c_process = send_ctrl_c(wait_interval)
|
||||
with db_connection().cursor() as cur:
|
||||
results = list(
|
||||
result for result in mycli.packages.special.iocommands.watch_query(arg="{0!s} {1!s}".format(watch_seconds, query), cur=cur)
|
||||
)
|
||||
results = list(mycli.packages.special.iocommands.watch_query(arg="{0!s} {1!s}".format(watch_seconds, query), cur=cur))
|
||||
ctrl_c_process.join(1)
|
||||
assert len(results) == expected_results
|
||||
for result in results:
|
||||
|
|
|
@ -61,8 +61,8 @@ def test_table_and_columns_query(executor):
|
|||
run(executor, "create table a(x text, y text)")
|
||||
run(executor, "create table b(z text)")
|
||||
|
||||
assert set(executor.tables()) == set([("a",), ("b",)])
|
||||
assert set(executor.table_columns()) == set([("a", "x"), ("a", "y"), ("b", "z")])
|
||||
assert set(executor.tables()) == {("a",), ("b",)}
|
||||
assert set(executor.table_columns()) == {("a", "x"), ("a", "y"), ("b", "z")}
|
||||
|
||||
|
||||
@dbtest
|
||||
|
|
4
tox.ini
4
tox.ini
|
@ -17,5 +17,5 @@ commands = uv pip install -e .[dev,ssh]
|
|||
[testenv:style]
|
||||
skip_install = true
|
||||
deps = ruff
|
||||
commands = ruff check --fix
|
||||
ruff format
|
||||
commands = ruff check
|
||||
ruff format --diff
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue