From 28b2f1129df01cf17d76069689d887330f50162f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 15 Mar 2019 12:53:20 +0100 Subject: [PATCH] Add console issue8126 review47821002 --- CHANGELOG | 1 + bin/trytond-console | 20 +++++++++++++ setup.py | 2 ++ trytond/commandline.py | 19 +++++++++++-- trytond/console.py | 64 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100755 bin/trytond-console create mode 100644 trytond/console.py diff --git a/CHANGELOG b/CHANGELOG index ac7e675edb..420eced77a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add console * Add Model.__names__ to retrieve model and field names * Add size attribute on image tag * Allow to use channel to synchronize Cache diff --git a/bin/trytond-console b/bin/trytond-console new file mode 100755 index 0000000000..c31b6ee201 --- /dev/null +++ b/bin/trytond-console @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. +import sys +import os + +DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, + '..', '..', 'trytond'))) +if os.path.isdir(DIR): + sys.path.insert(0, os.path.dirname(DIR)) + +import trytond.commandline as commandline +from trytond.config import config +import trytond.console as console + +parser = commandline.get_parser_console() +options = parser.parse_args() +config.update_etc(options.configfile) + +console.run(options) diff --git a/setup.py b/setup.py index 56e417b541..6b17b07c28 100755 --- a/setup.py +++ b/setup.py @@ -84,11 +84,13 @@ setup(name=name, scripts=[ 'bin/trytond', 'bin/trytond-admin', + 'bin/trytond-console', 'bin/trytond-cron', 'bin/trytond-worker', ], classifiers=[ 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', 'Environment :: No Input/Output (Daemon)', 'Framework :: Tryton', 'Intended Audience :: Developers', diff --git a/trytond/commandline.py b/trytond/commandline.py index 17d8595be5..341326ef7a 100644 --- a/trytond/commandline.py +++ b/trytond/commandline.py @@ -12,14 +12,19 @@ from trytond import __version__ logger = logging.getLogger(__name__) -def get_parser(): +def get_base_parser(): parser = argparse.ArgumentParser() - parser.add_argument('--version', action='version', version='%(prog)s ' + __version__) parser.add_argument("-c", "--config", dest="configfile", metavar='FILE', nargs='+', default=[os.environ.get('TRYTOND_CONFIG')], help='Specify configuration files') + return parser + + +def get_parser(): + parser = get_base_parser() + parser.add_argument("-v", "--verbose", action='count', dest="verbose", default=0, help="enable verbose mode") parser.add_argument('--dev', dest='dev', action='store_true', @@ -88,6 +93,16 @@ def get_parser_admin(): return parser +def get_parser_console(): + parser = get_base_parser() + parser.add_argument("-d", "--database", dest="database_name", + required=True, metavar='DATABASE', help="specify the database name") + parser.add_argument("--histsize", dest="histsize", type=int, default=500, + help="The number of commands to remember in the command history") + parser.epilog = "To store changes, `transaction.commit()` must be called." + return parser + + def config_log(options): if options.logconf: logging.config.fileConfig(options.logconf) diff --git a/trytond/console.py b/trytond/console.py new file mode 100644 index 0000000000..34c4c9df72 --- /dev/null +++ b/trytond/console.py @@ -0,0 +1,64 @@ +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. +import atexit +import os +import readline +import sys +from code import InteractiveConsole +from rlcompleter import Completer + +from trytond import __version__ +from trytond.pool import Pool +from trytond.transaction import Transaction +from trytond.worker import run_task + + +class Console(InteractiveConsole): + def __init__(self, locals=None, filename="", histsize=-1, + histfile=os.path.expanduser("~/.trytond_console_history")): + super().__init__(locals, filename) + self.init_completer(locals) + self.init_history(histfile, histsize) + + def init_completer(selfi, locals): + completer = Completer(locals) + readline.set_completer(completer.complete) + readline.parse_and_bind("tab: complete") + + def init_history(self, histfile, histsize): + readline.parse_and_bind("tab: complete") + if hasattr(readline, 'read_history_file'): + try: + readline.read_history_file(histfile) + except FileNotFoundError: + pass + atexit.register(self.save_history, histfile, histsize) + + def save_history(self, histfile, histsize): + readline.set_history_length(histsize) + readline.write_history_file(histfile) + + +def run(options): + db_name = options.database_name + pool = Pool(db_name) + with Transaction().start(db_name, 0, readonly=True): + pool.init() + + with Transaction().start(db_name, 0) as transaction: + local = { + 'pool': pool, + 'transaction': transaction, + } + if sys.stdin.isatty(): + console = Console(local, histsize=options.histsize) + banner = "Tryton %s, Python %s on %s" % ( + __version__, sys.version, sys.platform) + console.interact(banner=banner, exitmsg='') + else: + console = InteractiveConsole(local) + console.runcode(sys.stdin.read()) + transaction.rollback() + while transaction.tasks: + task_id = transaction.tasks.pop() + run_task(pool, task_id)