diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-10 10:18:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-10 10:18:43 +0000 |
commit | 44ba8147bbb1b651867b4b04e1711273d4a7281c (patch) | |
tree | d8c169e12006bfa46e436a180fd531aaac08aad5 | |
parent | Adding upstream version 1.9.0. (diff) | |
download | litecli-44ba8147bbb1b651867b4b04e1711273d4a7281c.tar.xz litecli-44ba8147bbb1b651867b4b04e1711273d4a7281c.zip |
Adding upstream version 1.10.0.upstream/1.10.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | .github/workflows/codeql.yml | 41 | ||||
-rw-r--r-- | .pre-commit-config.yaml | 2 | ||||
-rw-r--r-- | CHANGELOG.md | 25 | ||||
-rw-r--r-- | CONTRIBUTING.md | 4 | ||||
-rw-r--r-- | litecli/__init__.py | 2 | ||||
-rw-r--r-- | litecli/completion_refresher.py | 5 | ||||
-rw-r--r-- | litecli/key_bindings.py | 8 | ||||
-rw-r--r-- | litecli/liteclirc | 8 | ||||
-rw-r--r-- | litecli/main.py | 67 | ||||
-rw-r--r-- | litecli/packages/completion_engine.py | 2 | ||||
-rw-r--r-- | litecli/packages/parseutils.py | 2 | ||||
-rw-r--r-- | litecli/packages/special/dbcommands.py | 5 | ||||
-rw-r--r-- | litecli/packages/special/favoritequeries.py | 1 | ||||
-rw-r--r-- | litecli/packages/special/iocommands.py | 41 | ||||
-rw-r--r-- | litecli/packages/special/utils.py | 83 | ||||
-rw-r--r-- | litecli/sqlcompleter.py | 1 | ||||
-rw-r--r-- | litecli/sqlexecute.py | 29 | ||||
-rw-r--r-- | tasks.py | 3 | ||||
-rw-r--r-- | tests/liteclirc | 7 | ||||
-rw-r--r-- | tests/test_dbspecial.py | 14 | ||||
-rw-r--r-- | tests/test_main.py | 10 | ||||
-rw-r--r-- | tests/test_smart_completion_public_schema_only.py | 21 | ||||
-rw-r--r-- | tests/test_sqlexecute.py | 18 |
23 files changed, 299 insertions, 100 deletions
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..384b12f --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,41 @@ +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: "13 4 * * 0" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ python ] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + queries: +security-and-quality + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{ matrix.language }}" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 67ba03d..17fd047 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ repos: - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 23.11.0 hooks: - id: black diff --git a/CHANGELOG.md b/CHANGELOG.md index afeebd1..808b8df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +## 1.10.0 - 2022-11-19 + +### Features + +* Adding support for startup commands being set in liteclirc and executed on startup. Limited to commands already implemented in litecli. ([[#56](https://github.com/dbcli/litecli/issues/56)]) + +### Bug Fixes + +* Fix [[#146](https://github.com/dbcli/litecli/issues/146)], making sure `.once` + can be used more than once in a session. +* Fixed setting `successful = True` only when query is executed without exceptions so + failing queries get `successful = False` in `query_history`. +* Changed `master` to `main` in CONTRIBUTING.md to reflect GitHubs new default branch + naming. +* Fixed `.once -o <file>` by opening the output file once per statement instead + of for every line of output ([#148](https://github.com/dbcli/litecli/issues/148)). +* Use the sqlite3 API to cancel a running query on interrupt + ([#164](https://github.com/dbcli/litecli/issues/164)). +* Skip internal indexes in the .schema output + ([#170](https://github.com/dbcli/litecli/issues/170)). + + ## 1.9.0 - 2022-06-06 ### Features @@ -24,7 +46,7 @@ ### Bug Fixes * Upgrade cli_helpers to workaround Pygments regression. -* Use get_terminal_size from shutil instead of click. +* Use get_terminal_size from shutil instead of click. ## 1.7.0 - 2022-01-11 @@ -108,3 +130,4 @@ [Shawn Chapla]: https://github.com/shwnchpl [Zhaolong Zhu]: https://github.com/zzl0 [Zhiming Wang]: https://github.com/zmwangx +[Bjørnar Smestad]: https://brendesmestad.no diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9cd868a..a38d8d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,7 +49,7 @@ You'll always get credit for your work. $ pip install --editable . ``` -6. Create a branch for your bugfix or feature based off the `master` branch: +6. Create a branch for your bugfix or feature based off the `main` branch: ```bash $ git checkout -b <name-of-bugfix-or-feature> @@ -58,7 +58,7 @@ You'll always get credit for your work. 7. While you work on your bugfix or feature, be sure to pull the latest changes from `upstream`. This ensures that your local codebase is up-to-date: ```bash - $ git pull upstream master + $ git pull upstream main ``` 8. When your work is ready for the litecli team to review it, push your branch to your fork: diff --git a/litecli/__init__.py b/litecli/__init__.py index 0a0a43a..fcfdf38 100644 --- a/litecli/__init__.py +++ b/litecli/__init__.py @@ -1 +1 @@ -__version__ = "1.9.0" +__version__ = "1.10.0" diff --git a/litecli/completion_refresher.py b/litecli/completion_refresher.py index 9602070..bf36d03 100644 --- a/litecli/completion_refresher.py +++ b/litecli/completion_refresher.py @@ -7,7 +7,6 @@ from .sqlexecute import SQLExecute class CompletionRefresher(object): - refreshers = OrderedDict() def __init__(self): @@ -65,7 +64,7 @@ class CompletionRefresher(object): # if DB is memory, needed to use same connection executor = sqlexecute else: - # Create a new sqlexecute method to popoulate the completions. + # Create a new sqlexecute method to populate the completions. executor = SQLExecute(e.dbname) # If callbacks is a single function then push it into a list. @@ -79,7 +78,7 @@ class CompletionRefresher(object): self._restart_refresh.clear() break else: - # Break out of while loop if the for loop finishes natually + # Break out of while loop if the for loop finishes naturally # without hitting the break statement. break diff --git a/litecli/key_bindings.py b/litecli/key_bindings.py index 44d59d2..96eed50 100644 --- a/litecli/key_bindings.py +++ b/litecli/key_bindings.py @@ -81,4 +81,12 @@ def cli_bindings(cli): b = event.app.current_buffer b.complete_state = None + @kb.add("right", filter=completion_is_selected) + def _(event): + """Accept the completion that is selected in the dropdown menu.""" + _logger.debug("Detected right-arrow key.") + + b = event.app.current_buffer + b.complete_state = None + return kb diff --git a/litecli/liteclirc b/litecli/liteclirc index 4db6f3a..924b585 100644 --- a/litecli/liteclirc +++ b/litecli/liteclirc @@ -117,6 +117,12 @@ output.header = "#00ff5f bold" output.odd-row = "" output.even-row = "" - # Favorite queries. [favorite_queries] + +# Startup commands +# litecli commands or sqlite commands to be executed on startup. +# some of them will require you to have a database attached. +# they will be executed in the same order as they appear in the list. +[startup_commands] +#commands = ".tables", "pragma foreign_keys = ON;"
\ No newline at end of file diff --git a/litecli/main.py b/litecli/main.py index de279f6..e608da7 100644 --- a/litecli/main.py +++ b/litecli/main.py @@ -59,7 +59,6 @@ PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__)) class LiteCli(object): - default_prompt = "\\d> " max_len_prompt = 45 @@ -110,6 +109,13 @@ class LiteCli(object): fg="red", ) self.logfile = False + # Load startup commands. + try: + self.startup_commands = c["startup_commands"] + except ( + KeyError + ): # Redundant given the load_config() function that merges in the standard config, but put here to avoid fail if user do not have updated config file. + self.startup_commands = None self.completion_refresher = CompletionRefresher() @@ -230,7 +236,6 @@ class LiteCli(object): return [(None, None, None, "Changed prompt format to %s" % arg)] def initialize_logging(self): - log_file = self.config["main"]["log_file"] if log_file == "default": log_file = config_location() + "log" @@ -298,7 +303,6 @@ class LiteCli(object): return {x: get(x) for x in keys} def connect(self, database=""): - cnf = {"database": None} cnf = self.read_my_cnf_files(cnf.keys()) @@ -486,29 +490,17 @@ class LiteCli(object): except EOFError as e: raise e except KeyboardInterrupt: - # get last connection id - connection_id_to_kill = sqlexecute.connection_id - logger.debug("connection id to kill: %r", connection_id_to_kill) - # Restart connection to the database - sqlexecute.connect() try: - for title, cur, headers, status in sqlexecute.run( - "kill %s" % connection_id_to_kill - ): - status_str = str(status).lower() - if status_str.find("ok") > -1: - logger.debug( - "cancelled query, connection id: %r, sql: %r", - connection_id_to_kill, - text, - ) - self.echo("cancelled query", err=True, fg="red") + sqlexecute.conn.interrupt() except Exception as e: self.echo( "Encountered error while cancelling query: {}".format(e), err=True, fg="red", ) + else: + logger.debug("cancelled query") + self.echo("cancelled query", err=True, fg="red") except NotImplementedError: self.echo("Not Yet Implemented.", fg="yellow") except OperationalError as e: @@ -555,7 +547,6 @@ class LiteCli(object): complete_style = CompleteStyle.READLINE_LIKE with self._completer_lock: - if self.key_bindings == "vi": editing_mode = EditingMode.VI else: @@ -590,6 +581,42 @@ class LiteCli(object): search_ignore_case=True, ) + def startup_commands(): + if self.startup_commands: + if "commands" in self.startup_commands: + for command in self.startup_commands["commands"]: + try: + res = sqlexecute.run(command) + except Exception as e: + click.echo(command) + self.echo(str(e), err=True, fg="red") + else: + click.echo(command) + for title, cur, headers, status in res: + if title == "dot command not implemented": + self.echo( + "The SQLite dot command '" + + command.split(" ", 1)[0] + + "' is not yet implemented.", + fg="yellow", + ) + else: + output = self.format_output(title, cur, headers) + for line in output: + self.echo(line) + else: + self.echo( + "Could not read commands. The startup commands needs to be formatted as: \n commands = 'command1', 'command2', ...", + fg="yellow", + ) + + try: + startup_commands() + except Exception as e: + self.echo( + "Could not execute all startup commands: \n" + str(e), fg="yellow" + ) + try: while True: one_iteration() diff --git a/litecli/packages/completion_engine.py b/litecli/packages/completion_engine.py index 0e2a30f..31a32b7 100644 --- a/litecli/packages/completion_engine.py +++ b/litecli/packages/completion_engine.py @@ -210,7 +210,7 @@ def suggest_based_on_last_token(token, text_before_cursor, full_text, identifier # suggest columns that are present in more than one table return [{"type": "column", "tables": tables, "drop_unique": True}] elif p.token_first().value.lower() == "select": - # If the lparen is preceeded by a space chances are we're about to + # If the lparen is preceded by a space chances are we're about to # do a sub-select. if last_word(text_before_cursor, "all_punctuations").startswith("("): return [{"type": "keyword"}] diff --git a/litecli/packages/parseutils.py b/litecli/packages/parseutils.py index 3f5ca61..f5fdc1d 100644 --- a/litecli/packages/parseutils.py +++ b/litecli/packages/parseutils.py @@ -147,7 +147,7 @@ def extract_table_identifiers(token_stream): # extract_tables is inspired from examples in the sqlparse lib. def extract_tables(sql): - """Extract the table names from an SQL statment. + """Extract the table names from an SQL statement. Returns a list of (schema, table, alias) tuples diff --git a/litecli/packages/special/dbcommands.py b/litecli/packages/special/dbcommands.py index 203e1a8..dec3507 100644 --- a/litecli/packages/special/dbcommands.py +++ b/litecli/packages/special/dbcommands.py @@ -69,13 +69,14 @@ def show_schema(cur, arg=None, **_): args = (arg,) query = """ SELECT sql FROM sqlite_master - WHERE name==? + WHERE name==? AND sql IS NOT NULL ORDER BY tbl_name, type DESC, name """ else: args = tuple() query = """ SELECT sql FROM sqlite_master + WHERE sql IS NOT NULL ORDER BY tbl_name, type DESC, name """ @@ -212,7 +213,7 @@ def load_extension(cur, arg, **_): "Description of a table", arg_type=PARSED_QUERY, case_sensitive=True, - aliases=("\\d", "describe", "desc"), + aliases=("\\d", "desc"), ) def describe(cur, arg, **_): if arg: diff --git a/litecli/packages/special/favoritequeries.py b/litecli/packages/special/favoritequeries.py index 7da6fbf..8eab521 100644 --- a/litecli/packages/special/favoritequeries.py +++ b/litecli/packages/special/favoritequeries.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals class FavoriteQueries(object): - section_name = "favorite_queries" usage = """ diff --git a/litecli/packages/special/iocommands.py b/litecli/packages/special/iocommands.py index 43c3577..ee254f0 100644 --- a/litecli/packages/special/iocommands.py +++ b/litecli/packages/special/iocommands.py @@ -21,7 +21,7 @@ from litecli.packages.prompt_utils import confirm_destructive_query use_expanded_output = False PAGER_ENABLED = True tee_file = None -once_file = written_to_once_file = None +once_file = once_file_args = written_to_once_file = None favoritequeries = FavoriteQueries(ConfigObj()) @@ -286,7 +286,7 @@ def delete_favorite_query(arg, **_): return [(None, None, None, status)] -@special_command("system", "system [command]", "Execute a system shell commmand.") +@special_command("system", "system [command]", "Execute a system shell command.") def execute_system_command(arg, **_): """Execute a system shell command.""" usage = "Syntax: system [command].\n" @@ -377,9 +377,9 @@ def write_tee(output): aliases=("\\o", "\\once"), ) def set_once(arg, **_): - global once_file + global once_file_args - once_file = parseargfile(arg) + once_file_args = parseargfile(arg) return [(None, None, None, "")] @@ -387,27 +387,28 @@ def set_once(arg, **_): @export def write_once(output): global once_file, written_to_once_file - if output and once_file: - try: - f = open(**once_file) - except (IOError, OSError) as e: - once_file = None - raise OSError( - "Cannot write to file '{}': {}".format(e.filename, e.strerror) - ) - - with f: - click.echo(output, file=f, nl=False) - click.echo("\n", file=f, nl=False) + if output and once_file_args: + if once_file is None: + try: + once_file = open(**once_file_args) + except (IOError, OSError) as e: + once_file = None + raise OSError( + "Cannot write to file '{}': {}".format(e.filename, e.strerror) + ) + + click.echo(output, file=once_file, nl=False) + click.echo("\n", file=once_file, nl=False) written_to_once_file = True @export def unset_once_if_written(): """Unset the once file, if it has been written to.""" - global once_file - if written_to_once_file: - once_file = None + global once_file, once_file_args, written_to_once_file + if once_file and written_to_once_file: + once_file.close() + once_file = once_file_args = written_to_once_file = None @special_command( @@ -461,7 +462,7 @@ def watch_query(arg, **kwargs): # Somewhere in the code the pager its activated after every yield, # so we disable it in every iteration set_pager_enabled(False) - for (sql, title) in sql_list: + for sql, title in sql_list: cur.execute(sql) if cur.description: headers = [x[0] for x in cur.description] diff --git a/litecli/packages/special/utils.py b/litecli/packages/special/utils.py index eed9306..4d3ad91 100644 --- a/litecli/packages/special/utils.py +++ b/litecli/packages/special/utils.py @@ -46,3 +46,86 @@ def format_uptime(uptime_in_seconds): uptime = " ".join(uptime_values) return uptime + + +def check_if_sqlitedotcommand(command): + """Does a check if the command supplied is in the list of SQLite dot commands. + + :param command: A command (str) supplied from the user + :returns: True/False + """ + + sqlite3dotcommands = [ + ".archive", + ".auth", + ".backup", + ".bail", + ".binary", + ".cd", + ".changes", + ".check", + ".clone", + ".connection", + ".databases", + ".dbconfig", + ".dbinfo", + ".dump", + ".echo", + ".eqp", + ".excel", + ".exit", + ".expert", + ".explain", + ".filectrl", + ".fullschema", + ".headers", + ".help", + ".import", + ".imposter", + ".indexes", + ".limit", + ".lint", + ".load", + ".log", + ".mode", + ".nonce", + ".nullvalue", + ".once", + ".open", + ".output", + ".parameter", + ".print", + ".progress", + ".prompt", + ".quit", + ".read", + ".recover", + ".restore", + ".save", + ".scanstats", + ".schema", + ".selftest", + ".separator", + ".session", + ".sha3sum", + ".shell", + ".show", + ".stats", + ".system", + ".tables", + ".testcase", + ".testctrl", + ".timeout", + ".timer", + ".trace", + ".vfsinfo", + ".vfslist", + ".vfsname", + ".width", + ] + + if isinstance(command, str): + command = command.split(" ", 1)[0].lower() + return command in sqlite3dotcommands + else: + return False diff --git a/litecli/sqlcompleter.py b/litecli/sqlcompleter.py index 64ca352..82b8d87 100644 --- a/litecli/sqlcompleter.py +++ b/litecli/sqlcompleter.py @@ -448,7 +448,6 @@ class SQLCompleter(Completer): suggestions = suggest_type(document.text, document.text_before_cursor) for suggestion in suggestions: - _logger.debug("Suggestion type: %r", suggestion["type"]) if suggestion["type"] == "column": diff --git a/litecli/sqlexecute.py b/litecli/sqlexecute.py index 3f78d49..2392472 100644 --- a/litecli/sqlexecute.py +++ b/litecli/sqlexecute.py @@ -1,8 +1,8 @@ import logging import sqlite3 -import uuid from contextlib import closing from sqlite3 import OperationalError +from litecli.packages.special.utils import check_if_sqlitedotcommand import sqlparse import os.path @@ -18,7 +18,6 @@ _logger = logging.getLogger(__name__) class SQLExecute(object): - databases_query = """ PRAGMA database_list """ @@ -51,7 +50,6 @@ class SQLExecute(object): def __init__(self, database): self.dbname = database self._server_type = None - self.connection_id = None self.conn = None if not database: _logger.debug("Database is not specified. Skip connection.") @@ -76,8 +74,6 @@ class SQLExecute(object): # Update them after the connection is made to ensure that it was a # successful connection. self.dbname = db - # retrieve connection id - self.reset_connection_id() def run(self, statement): """Execute the sql in the database and return the results. The results @@ -129,9 +125,12 @@ class SQLExecute(object): for result in special.execute(cur, sql): yield result except special.CommandNotFound: # Regular SQL - _logger.debug("Regular sql statement. sql: %r", sql) - cur.execute(sql) - yield self.get_result(cur) + if check_if_sqlitedotcommand(sql): + yield ("dot command not implemented", None, None, None) + else: + _logger.debug("Regular sql statement. sql: %r", sql) + cur.execute(sql) + yield self.get_result(cur) def get_result(self, cursor): """Get the current result's data from the cursor.""" @@ -204,17 +203,3 @@ class SQLExecute(object): def server_type(self): self._server_type = ("sqlite3", "3") return self._server_type - - def get_connection_id(self): - if not self.connection_id: - self.reset_connection_id() - return self.connection_id - - def reset_connection_id(self): - # Remember current connection id - _logger.debug("Get current connection id") - # res = self.run('select connection_id()') - self.connection_id = uuid.uuid4() - # for title, cur, headers, status in res: - # self.connection_id = cur.fetchone()[0] - _logger.debug("Current connection id: %s", self.connection_id) @@ -34,7 +34,7 @@ class BaseCommand(Command, object): sys.exit(subprocess.call(cmd, shell=shell)) def call_in_sequence(self, cmds, shell=True): - """Run multiple commmands in a row, exiting if one fails.""" + """Run multiple commands in a row, exiting if one fails.""" for cmd in cmds: if subprocess.call(cmd, shell=shell) == 1: sys.exit(1) @@ -75,7 +75,6 @@ class lint(BaseCommand): class test(TestCommand): - user_options = [("pytest-args=", "a", "Arguments to pass to pytest")] def initialize_options(self): diff --git a/tests/liteclirc b/tests/liteclirc index da9b061..21a3ef9 100644 --- a/tests/liteclirc +++ b/tests/liteclirc @@ -135,3 +135,10 @@ Token.Toolbar.Arg.Text = nobold [favorite_queries] q_param = select * from test where name=? sh_param = select * from test where id=$1 + +# Startup commands +# litecli commands or sqlite commands to be executed on startup. +# some of them will require you to have a database attached. +# they will be executed in the same order as they appear in the list. +[startup_commands] +commands = "create table startupcommands(a text)", "insert into startupcommands values('abc')" diff --git a/tests/test_dbspecial.py b/tests/test_dbspecial.py index 5128b5b..d3c7c07 100644 --- a/tests/test_dbspecial.py +++ b/tests/test_dbspecial.py @@ -1,6 +1,7 @@ from litecli.packages.completion_engine import suggest_type from test_completion_engine import sorted_dicts from litecli.packages.special.utils import format_uptime +from litecli.packages.special.utils import check_if_sqlitedotcommand def test_import_first_argument(): @@ -74,3 +75,16 @@ def test_indexes(): {"type": "schema"}, ] ) + + +def test_check_if_sqlitedotcommand(): + test_cases = [ + [".tables", True], + [".BiNarY", True], + ["binary", False], + [234, False], + [".changes test! test", True], + ["NotDotcommand", False], + ] + for command, expected_result in test_cases: + assert check_if_sqlitedotcommand(command) == expected_result diff --git a/tests/test_main.py b/tests/test_main.py index d4d52af..e2f183a 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -260,3 +260,13 @@ def test_import_command(executor): """ assert result.exit_code == 0 assert expected in "".join(result.output) + + +def test_startup_commands(executor): + m = LiteCli(liteclirc=default_config_file) + assert m.startup_commands["commands"] == [ + "create table startupcommands(a text)", + "insert into startupcommands values('abc')", + ] + + # implement tests on executions of the startupcommands diff --git a/tests/test_smart_completion_public_schema_only.py b/tests/test_smart_completion_public_schema_only.py index e532118..c8e1be4 100644 --- a/tests/test_smart_completion_public_schema_only.py +++ b/tests/test_smart_completion_public_schema_only.py @@ -15,7 +15,6 @@ metadata = { @pytest.fixture def completer(): - import litecli.sqlcompleter as sqlcompleter comp = sqlcompleter.SQLCompleter() @@ -367,17 +366,15 @@ def test_auto_escaped_col_names(completer, complete_event): Document(text=text, cursor_position=position), complete_event ) ) - assert ( - result - == [ - Completion(text="*", start_position=0), - Completion(text="`ABC`", start_position=0), - Completion(text="`insert`", start_position=0), - Completion(text="id", start_position=0), - ] - + list(map(Completion, completer.functions)) - + [Completion(text="`select`", start_position=0)] - + list(map(Completion, sorted(completer.keywords))) + assert result == [ + Completion(text="*", start_position=0), + Completion(text="`ABC`", start_position=0), + Completion(text="`insert`", start_position=0), + Completion(text="id", start_position=0), + ] + list(map(Completion, completer.functions)) + [ + Completion(text="select", start_position=0) + ] + list( + map(Completion, sorted(completer.keywords)) ) diff --git a/tests/test_sqlexecute.py b/tests/test_sqlexecute.py index e559bc6..16bad74 100644 --- a/tests/test_sqlexecute.py +++ b/tests/test_sqlexecute.py @@ -94,11 +94,11 @@ def test_invalid_column_name(executor): @dbtest def test_unicode_support_in_output(executor): run(executor, "create table unicodechars(t text)") - run(executor, u"insert into unicodechars (t) values ('é')") + run(executor, "insert into unicodechars (t) values ('é')") # See issue #24, this raises an exception without proper handling - results = run(executor, u"select * from unicodechars") - assert_result_equal(results, headers=["t"], rows=[(u"é",)]) + results = run(executor, "select * from unicodechars") + assert_result_equal(results, headers=["t"], rows=[("é",)]) @dbtest @@ -106,9 +106,9 @@ def test_invalid_unicode_values_dont_choke(executor): run(executor, "create table unicodechars(t text)") # \xc3 is not a valid utf-8 char. But we can insert it into the database # which can break querying if not handled correctly. - run(executor, u"insert into unicodechars (t) values (cast(x'c3' as text))") + run(executor, "insert into unicodechars (t) values (cast(x'c3' as text))") - results = run(executor, u"select * from unicodechars") + results = run(executor, "select * from unicodechars") assert_result_equal(results, headers=["t"], rows=[("\\xc3",)]) @@ -120,13 +120,13 @@ def test_multiple_queries_same_line(executor): { "title": None, "headers": ["'foo'"], - "rows": [(u"foo",)], + "rows": [("foo",)], "status": "1 row in set", }, { "title": None, "headers": ["'bar'"], - "rows": [(u"bar",)], + "rows": [("bar",)], "status": "1 row in set", }, ] @@ -369,8 +369,8 @@ def test_cd_command_current_dir(executor): @dbtest def test_unicode_support(executor): - results = run(executor, u"SELECT '日本語' AS japanese;") - assert_result_equal(results, headers=["japanese"], rows=[(u"日本語",)]) + results = run(executor, "SELECT '日本語' AS japanese;") + assert_result_equal(results, headers=["japanese"], rows=[("日本語",)]) @dbtest |