From 24512aac081d1e30ad52805606b42411f1aed861 Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Thu, 24 May 2018 22:26:59 +0200 Subject: Updated SQLite tutorial with new images and small improvements. --- docs/images/repl/1.png | Bin 70421 -> 0 bytes docs/images/repl/2.png | Bin 85031 -> 0 bytes docs/images/repl/3.png | Bin 75365 -> 0 bytes docs/images/repl/4.png | Bin 61473 -> 0 bytes docs/images/repl/5.png | Bin 67403 -> 0 bytes docs/images/repl/6.png | Bin 47881 -> 0 bytes docs/images/repl/sqlite-1.png | Bin 0 -> 125880 bytes docs/images/repl/sqlite-2.png | Bin 0 -> 171192 bytes docs/images/repl/sqlite-3.png | Bin 0 -> 126517 bytes docs/images/repl/sqlite-4.png | Bin 0 -> 190998 bytes docs/images/repl/sqlite-5.png | Bin 0 -> 182631 bytes docs/images/repl/sqlite-6.png | Bin 0 -> 200352 bytes docs/pages/tutorials/repl.rst | 116 +++++++++++++++++++++++++++++--------- examples/tutorial/sqlite-cli.py | 35 +++++++++--- prompt_toolkit/layout/controls.py | 2 +- 15 files changed, 116 insertions(+), 37 deletions(-) delete mode 100644 docs/images/repl/1.png delete mode 100644 docs/images/repl/2.png delete mode 100644 docs/images/repl/3.png delete mode 100644 docs/images/repl/4.png delete mode 100644 docs/images/repl/5.png delete mode 100644 docs/images/repl/6.png create mode 100644 docs/images/repl/sqlite-1.png create mode 100644 docs/images/repl/sqlite-2.png create mode 100644 docs/images/repl/sqlite-3.png create mode 100644 docs/images/repl/sqlite-4.png create mode 100644 docs/images/repl/sqlite-5.png create mode 100644 docs/images/repl/sqlite-6.png diff --git a/docs/images/repl/1.png b/docs/images/repl/1.png deleted file mode 100644 index 63362c23..00000000 Binary files a/docs/images/repl/1.png and /dev/null differ diff --git a/docs/images/repl/2.png b/docs/images/repl/2.png deleted file mode 100644 index f9ddb100..00000000 Binary files a/docs/images/repl/2.png and /dev/null differ diff --git a/docs/images/repl/3.png b/docs/images/repl/3.png deleted file mode 100644 index e62264da..00000000 Binary files a/docs/images/repl/3.png and /dev/null differ diff --git a/docs/images/repl/4.png b/docs/images/repl/4.png deleted file mode 100644 index 0e75323c..00000000 Binary files a/docs/images/repl/4.png and /dev/null differ diff --git a/docs/images/repl/5.png b/docs/images/repl/5.png deleted file mode 100644 index 3c0f159a..00000000 Binary files a/docs/images/repl/5.png and /dev/null differ diff --git a/docs/images/repl/6.png b/docs/images/repl/6.png deleted file mode 100644 index d3405cc0..00000000 Binary files a/docs/images/repl/6.png and /dev/null differ diff --git a/docs/images/repl/sqlite-1.png b/docs/images/repl/sqlite-1.png new file mode 100644 index 00000000..0511daa0 Binary files /dev/null and b/docs/images/repl/sqlite-1.png differ diff --git a/docs/images/repl/sqlite-2.png b/docs/images/repl/sqlite-2.png new file mode 100644 index 00000000..47b02382 Binary files /dev/null and b/docs/images/repl/sqlite-2.png differ diff --git a/docs/images/repl/sqlite-3.png b/docs/images/repl/sqlite-3.png new file mode 100644 index 00000000..cdee9d20 Binary files /dev/null and b/docs/images/repl/sqlite-3.png differ diff --git a/docs/images/repl/sqlite-4.png b/docs/images/repl/sqlite-4.png new file mode 100644 index 00000000..c6ee9297 Binary files /dev/null and b/docs/images/repl/sqlite-4.png differ diff --git a/docs/images/repl/sqlite-5.png b/docs/images/repl/sqlite-5.png new file mode 100644 index 00000000..d1964e02 Binary files /dev/null and b/docs/images/repl/sqlite-5.png differ diff --git a/docs/images/repl/sqlite-6.png b/docs/images/repl/sqlite-6.png new file mode 100644 index 00000000..054beb05 Binary files /dev/null and b/docs/images/repl/sqlite-6.png differ diff --git a/docs/pages/tutorials/repl.rst b/docs/pages/tutorials/repl.rst index 6aac7a51..7d7bba13 100644 --- a/docs/pages/tutorials/repl.rst +++ b/docs/pages/tutorials/repl.rst @@ -33,7 +33,7 @@ function as a good practise. if __name__ == '__main__': main() -.. image:: ../../images/repl/1.png +.. image:: ../../images/repl/sqlite-1.png Loop The REPL @@ -75,7 +75,7 @@ respectively. if __name__ == '__main__': main() -.. image:: ../../images/repl/2.png +.. image:: ../../images/repl/sqlite-2.png Syntax Highlighting @@ -114,14 +114,15 @@ wrapped into a :class:`~prompt_toolkit.lexers.PygmentsLexer`. if __name__ == '__main__': main() -.. image:: ../../images/repl/3.png +.. image:: ../../images/repl/sqlite-3.png Auto-completion --------------- -Now we are going to add auto completion. We'd like a drop down menu of possible -keywords when the user is typing. +Now we are going to add auto completion. We'd like a drop down menu of +`possible keywords `_ when the user +is typing. Create your ``sql_completer`` instance from the ``WordCompleter`` class defining a set of ``keywords`` for auto-completion. @@ -138,9 +139,26 @@ Like the lexer, this ``sql_completer`` instance can be passed to either the from prompt_toolkit.lexers import PygmentsLexer from pygments.lexers import SqlLexer - sql_completer = WordCompleter( - ['create', 'select', 'insert', 'drop', 'delete', 'from', 'where', 'table'], - ignore_case=True) + sql_completer = WordCompleter([ + 'abort', 'action', 'add', 'after', 'all', 'alter', 'analyze', 'and', + 'as', 'asc', 'attach', 'autoincrement', 'before', 'begin', 'between', + 'by', 'cascade', 'case', 'cast', 'check', 'collate', 'column', + 'commit', 'conflict', 'constraint', 'create', 'cross', 'current_date', + 'current_time', 'current_timestamp', 'database', 'default', + 'deferrable', 'deferred', 'delete', 'desc', 'detach', 'distinct', + 'drop', 'each', 'else', 'end', 'escape', 'except', 'exclusive', + 'exists', 'explain', 'fail', 'for', 'foreign', 'from', 'full', 'glob', + 'group', 'having', 'if', 'ignore', 'immediate', 'in', 'index', + 'indexed', 'initially', 'inner', 'insert', 'instead', 'intersect', + 'into', 'is', 'isnull', 'join', 'key', 'left', 'like', 'limit', + 'match', 'natural', 'no', 'not', 'notnull', 'null', 'of', 'offset', + 'on', 'or', 'order', 'outer', 'plan', 'pragma', 'primary', 'query', + 'raise', 'recursive', 'references', 'regexp', 'reindex', 'release', + 'rename', 'replace', 'restrict', 'right', 'rollback', 'row', + 'savepoint', 'select', 'set', 'table', 'temp', 'temporary', 'then', + 'to', 'transaction', 'trigger', 'union', 'unique', 'update', 'using', + 'vacuum', 'values', 'view', 'virtual', 'when', 'where', 'with', + 'without'], ignore_case=True) def main(): session = PromptSession( @@ -160,7 +178,7 @@ Like the lexer, this ``sql_completer`` instance can be passed to either the if __name__ == '__main__': main() -.. image:: ../../images/repl/4.png +.. image:: ../../images/repl/sqlite-4.png In about 30 lines of code we got ourselves an auto completing, syntax highlighting REPL. Let's make it better. @@ -183,14 +201,32 @@ function. from prompt_toolkit.styles import Style from pygments.lexers import SqlLexer - sql_completer = WordCompleter( - ['create', 'select', 'insert', 'drop', 'delete', 'from', 'where', 'table'], - ignore_case=True) - + sql_completer = WordCompleter([ + 'abort', 'action', 'add', 'after', 'all', 'alter', 'analyze', 'and', + 'as', 'asc', 'attach', 'autoincrement', 'before', 'begin', 'between', + 'by', 'cascade', 'case', 'cast', 'check', 'collate', 'column', + 'commit', 'conflict', 'constraint', 'create', 'cross', 'current_date', + 'current_time', 'current_timestamp', 'database', 'default', + 'deferrable', 'deferred', 'delete', 'desc', 'detach', 'distinct', + 'drop', 'each', 'else', 'end', 'escape', 'except', 'exclusive', + 'exists', 'explain', 'fail', 'for', 'foreign', 'from', 'full', 'glob', + 'group', 'having', 'if', 'ignore', 'immediate', 'in', 'index', + 'indexed', 'initially', 'inner', 'insert', 'instead', 'intersect', + 'into', 'is', 'isnull', 'join', 'key', 'left', 'like', 'limit', + 'match', 'natural', 'no', 'not', 'notnull', 'null', 'of', 'offset', + 'on', 'or', 'order', 'outer', 'plan', 'pragma', 'primary', 'query', + 'raise', 'recursive', 'references', 'regexp', 'reindex', 'release', + 'rename', 'replace', 'restrict', 'right', 'rollback', 'row', + 'savepoint', 'select', 'set', 'table', 'temp', 'temporary', 'then', + 'to', 'transaction', 'trigger', 'union', 'unique', 'update', 'using', + 'vacuum', 'values', 'view', 'virtual', 'when', 'where', 'with', + 'without'], ignore_case=True) style = Style.from_dict({ - 'completion-menu.current-completion': 'bg:#00aaaa #000000', 'completion-menu.completion': 'bg:#008888 #ffffff', + 'completion-menu.completion.current': 'bg:#00aaaa #000000', + 'scrollbar.background': 'bg:#88aaaa', + 'scrollbar.button': 'bg:#222222', }) def main(): @@ -211,7 +247,7 @@ function. if __name__ == '__main__': main() -.. image:: ../../images/repl/5.png +.. image:: ../../images/repl/sqlite-5.png All that's left is hooking up the sqlite backend, which is left as an exercise for the reader. Just kidding... Keep reading. @@ -220,49 +256,75 @@ for the reader. Just kidding... Keep reading. Hook up Sqlite -------------- -This step is totally optional ;). So far we've been focusing on building the -REPL. Now it's time to relay the input to SQLite. +This step is the final step to make the SQLite REPL actually work. It's time +to relay the input to SQLite. Obviously I haven't done the due diligence to deal with the errors. But it gives a good idea of how to get started. .. code:: python + #!/usr/bin/env python from __future__ import unicode_literals import sys import sqlite3 from prompt_toolkit import PromptSession from prompt_toolkit.completion import WordCompleter + from prompt_toolkit.lexers import PygmentsLexer from prompt_toolkit.styles import Style from pygments.lexers import SqlLexer - sql_completer = WordCompleter( - ['create', 'select', 'insert', 'drop', 'delete', 'from', 'where', 'table'], - ignore_case=True) + sql_completer = WordCompleter([ + 'abort', 'action', 'add', 'after', 'all', 'alter', 'analyze', 'and', + 'as', 'asc', 'attach', 'autoincrement', 'before', 'begin', 'between', + 'by', 'cascade', 'case', 'cast', 'check', 'collate', 'column', + 'commit', 'conflict', 'constraint', 'create', 'cross', 'current_date', + 'current_time', 'current_timestamp', 'database', 'default', + 'deferrable', 'deferred', 'delete', 'desc', 'detach', 'distinct', + 'drop', 'each', 'else', 'end', 'escape', 'except', 'exclusive', + 'exists', 'explain', 'fail', 'for', 'foreign', 'from', 'full', 'glob', + 'group', 'having', 'if', 'ignore', 'immediate', 'in', 'index', + 'indexed', 'initially', 'inner', 'insert', 'instead', 'intersect', + 'into', 'is', 'isnull', 'join', 'key', 'left', 'like', 'limit', + 'match', 'natural', 'no', 'not', 'notnull', 'null', 'of', 'offset', + 'on', 'or', 'order', 'outer', 'plan', 'pragma', 'primary', 'query', + 'raise', 'recursive', 'references', 'regexp', 'reindex', 'release', + 'rename', 'replace', 'restrict', 'right', 'rollback', 'row', + 'savepoint', 'select', 'set', 'table', 'temp', 'temporary', 'then', + 'to', 'transaction', 'trigger', 'union', 'unique', 'update', 'using', + 'vacuum', 'values', 'view', 'virtual', 'when', 'where', 'with', + 'without'], ignore_case=True) style = Style.from_dict({ - 'completion-menu.current-completion': 'bg:#00aaaa #000000', 'completion-menu.completion': 'bg:#008888 #ffffff', + 'completion-menu.completion.current': 'bg:#00aaaa #000000', + 'scrollbar.background': 'bg:#88aaaa', + 'scrollbar.button': 'bg:#222222', }) def main(database): connection = sqlite3.connect(database) session = PromptSession( - lexer=SqlLexer, completer=sql_completer, style=style) + lexer=PygmentsLexer(SqlLexer), completer=sql_completer, style=style) while True: try: text = session.prompt('> ') except KeyboardInterrupt: - continue # Control-C pressed. Try again. + continue # Control-C pressed. Try again. except EOFError: break # Control-D pressed. with connection: - messages = connection.execute(text) - for message in messages: - print(message) + try: + messages = connection.execute(text) + except Exception as e: + print(repr(e)) + else: + for message in messages: + print(message) + print('GoodBye!') if __name__ == '__main__': @@ -273,7 +335,7 @@ gives a good idea of how to get started. main(db) -.. image:: ../../images/repl/6.png +.. image:: ../../images/repl/sqlite-6.png I hope that gives an idea of how to get started on building command line interfaces. diff --git a/examples/tutorial/sqlite-cli.py b/examples/tutorial/sqlite-cli.py index da9abda9..04cf259e 100755 --- a/examples/tutorial/sqlite-cli.py +++ b/examples/tutorial/sqlite-cli.py @@ -1,25 +1,42 @@ #!/usr/bin/env python -from __future__ import unicode_literals +from __future__ import unicode_literals, print_function import sys import sqlite3 from prompt_toolkit import PromptSession from prompt_toolkit.completion import WordCompleter -from prompt_toolkit.styles import Style from prompt_toolkit.lexers import PygmentsLexer - +from prompt_toolkit.styles import Style from pygments.lexers import SqlLexer -sql_completer = WordCompleter( - ['create', 'select', 'insert', 'drop', 'delete', 'from', 'where', 'table'], - ignore_case=True) +sql_completer = WordCompleter([ + 'abort', 'action', 'add', 'after', 'all', 'alter', 'analyze', 'and', + 'as', 'asc', 'attach', 'autoincrement', 'before', 'begin', 'between', + 'by', 'cascade', 'case', 'cast', 'check', 'collate', 'column', + 'commit', 'conflict', 'constraint', 'create', 'cross', 'current_date', + 'current_time', 'current_timestamp', 'database', 'default', + 'deferrable', 'deferred', 'delete', 'desc', 'detach', 'distinct', + 'drop', 'each', 'else', 'end', 'escape', 'except', 'exclusive', + 'exists', 'explain', 'fail', 'for', 'foreign', 'from', 'full', 'glob', + 'group', 'having', 'if', 'ignore', 'immediate', 'in', 'index', + 'indexed', 'initially', 'inner', 'insert', 'instead', 'intersect', + 'into', 'is', 'isnull', 'join', 'key', 'left', 'like', 'limit', + 'match', 'natural', 'no', 'not', 'notnull', 'null', 'of', 'offset', + 'on', 'or', 'order', 'outer', 'plan', 'pragma', 'primary', 'query', + 'raise', 'recursive', 'references', 'regexp', 'reindex', 'release', + 'rename', 'replace', 'restrict', 'right', 'rollback', 'row', + 'savepoint', 'select', 'set', 'table', 'temp', 'temporary', 'then', + 'to', 'transaction', 'trigger', 'union', 'unique', 'update', 'using', + 'vacuum', 'values', 'view', 'virtual', 'when', 'where', 'with', + 'without'], ignore_case=True) style = Style.from_dict({ - 'completion-menu.current-completion': 'bg:#00aaaa #000000', 'completion-menu.completion': 'bg:#008888 #ffffff', + 'completion-menu.completion.current': 'bg:#00aaaa #000000', + 'scrollbar.background': 'bg:#88aaaa', + 'scrollbar.button': 'bg:#222222', }) - def main(database): connection = sqlite3.connect(database) session = PromptSession( @@ -41,8 +58,8 @@ def main(database): else: for message in messages: print(message) - print('GoodBye!') + print('GoodBye!') if __name__ == '__main__': if len(sys.argv) < 2: diff --git a/prompt_toolkit/layout/controls.py b/prompt_toolkit/layout/controls.py index eca0c61e..b387f87b 100644 --- a/prompt_toolkit/layout/controls.py +++ b/prompt_toolkit/layout/controls.py @@ -423,7 +423,7 @@ class BufferControl(UIControl): assert input_processors is None or isinstance(input_processors, list) assert isinstance(include_default_input_processors, bool) assert menu_position is None or callable(menu_position) - assert lexer is None or isinstance(lexer, Lexer) + assert lexer is None or isinstance(lexer, Lexer), 'Got %r' % (lexer, ) assert (search_buffer_control is None or callable(search_buffer_control) or isinstance(search_buffer_control, SearchBufferControl)) -- cgit v1.2.3