gOdoo-cli 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- godoo_cli/__init__.py +2 -0
- godoo_cli/__main__.py +5 -0
- godoo_cli/cli.py +87 -0
- godoo_cli/cli_common.py +183 -0
- godoo_cli/commands/__init__.py +9 -0
- godoo_cli/commands/backup/__init__.py +1 -0
- godoo_cli/commands/backup/cli.py +17 -0
- godoo_cli/commands/backup/load.py +110 -0
- godoo_cli/commands/backup/pull.py +134 -0
- godoo_cli/commands/backup/util.py +35 -0
- godoo_cli/commands/bootstrap.py +187 -0
- godoo_cli/commands/config.py +43 -0
- godoo_cli/commands/db/__init__.py +1 -0
- godoo_cli/commands/db/cli.py +18 -0
- godoo_cli/commands/db/connection.py +94 -0
- godoo_cli/commands/db/passwords.py +56 -0
- godoo_cli/commands/db/query.py +41 -0
- godoo_cli/commands/launch.py +325 -0
- godoo_cli/commands/rpc/__init__.py +8 -0
- godoo_cli/commands/rpc/cli.py +34 -0
- godoo_cli/commands/rpc/config_parameters.py +48 -0
- godoo_cli/commands/rpc/importer.py +70 -0
- godoo_cli/commands/rpc/modules.py +144 -0
- godoo_cli/commands/rpc/translations.py +129 -0
- godoo_cli/commands/shell.py +45 -0
- godoo_cli/commands/source_get.py +279 -0
- godoo_cli/commands/test.py +126 -0
- godoo_cli/git/__init__.py +4 -0
- godoo_cli/git/git_odoo.py +89 -0
- godoo_cli/git/git_odoo_addons.py +95 -0
- godoo_cli/git/git_repo.py +207 -0
- godoo_cli/git/git_url.py +152 -0
- godoo_cli/git/zip_download.py +49 -0
- godoo_cli/helpers/__init__.py +1 -0
- godoo_cli/helpers/bootstrap.py +61 -0
- godoo_cli/helpers/cli.py +15 -0
- godoo_cli/helpers/odoo_files.py +278 -0
- godoo_cli/helpers/odoo_manifest.py +112 -0
- godoo_cli/helpers/system.py +176 -0
- godoo_cli/version.py +1 -0
- godoo_cli-0.7.0.dist-info/LICENSE +165 -0
- godoo_cli-0.7.0.dist-info/METADATA +197 -0
- godoo_cli-0.7.0.dist-info/RECORD +45 -0
- godoo_cli-0.7.0.dist-info/WHEEL +4 -0
- godoo_cli-0.7.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, List
|
|
6
|
+
|
|
7
|
+
from ..cli_common import CommonCLI
|
|
8
|
+
from ..helpers.bootstrap import _install_py_reqs_by_odoo_cmd
|
|
9
|
+
from ..helpers.odoo_files import get_addon_paths, get_odoo_module_paths
|
|
10
|
+
from ..helpers.system import run_cmd
|
|
11
|
+
|
|
12
|
+
CLI = CommonCLI()
|
|
13
|
+
|
|
14
|
+
LOGGER = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _add_default_argument(cmd_list: List[str], arg: str, arg_val: Any):
|
|
18
|
+
if not any([arg in s for s in cmd_list]):
|
|
19
|
+
cmd_list.append(f'{arg}="{arg_val}"')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _boostrap_command(
|
|
23
|
+
odoo_main_path: Path,
|
|
24
|
+
odoo_conf_path: Path,
|
|
25
|
+
addon_paths: List[Path],
|
|
26
|
+
workspace_addon_path: Path,
|
|
27
|
+
db_host: str,
|
|
28
|
+
db_filter: str,
|
|
29
|
+
db_name: str,
|
|
30
|
+
db_user: str,
|
|
31
|
+
db_password: str,
|
|
32
|
+
db_port: str,
|
|
33
|
+
extra_cmd_args: List[str] = None,
|
|
34
|
+
install_base: bool = True,
|
|
35
|
+
install_workspace_modules: bool = True,
|
|
36
|
+
multithread_worker_count: int = -1,
|
|
37
|
+
languages: str = "de_DE,en_US",
|
|
38
|
+
) -> str:
|
|
39
|
+
"""
|
|
40
|
+
Generate Bootstrap Command.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
odoo_main_path : Path
|
|
45
|
+
folder with odoo-bin
|
|
46
|
+
odoo_conf_path : Path
|
|
47
|
+
path to odoo.conf
|
|
48
|
+
addon_paths : List[Path]
|
|
49
|
+
odoo bin --addons-path
|
|
50
|
+
workspace_addon_path : Path
|
|
51
|
+
path to addons in dev repo
|
|
52
|
+
db_filter : str
|
|
53
|
+
db filter for odoo.conf
|
|
54
|
+
db_host : str
|
|
55
|
+
db hostname for odoo.conf
|
|
56
|
+
db_name : str
|
|
57
|
+
database name for odoo.conf
|
|
58
|
+
db_user : str
|
|
59
|
+
db user
|
|
60
|
+
db_password : str
|
|
61
|
+
db user password
|
|
62
|
+
db_port : str
|
|
63
|
+
db host port
|
|
64
|
+
extra_cmd_args : List[str], optional
|
|
65
|
+
extra args to pass to odoo-bin, by default None
|
|
66
|
+
install_base : bool, optional
|
|
67
|
+
install base,web, by default True
|
|
68
|
+
install_workspace_modules : bool, optional
|
|
69
|
+
install all modules found in workspace_path, by default True
|
|
70
|
+
multithread_worker_count : int, optional
|
|
71
|
+
cound of threads. if >0 cli also sets proxy mode flag, by default 9
|
|
72
|
+
languages : str, optional
|
|
73
|
+
languages to load, by default "de_DE,en_US"
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
str
|
|
78
|
+
odoo-bin command
|
|
79
|
+
"""
|
|
80
|
+
LOGGER.info("Generating Bootstrap Command")
|
|
81
|
+
|
|
82
|
+
odoo_conf_path.parent.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
|
|
84
|
+
db_command = [
|
|
85
|
+
f"--database {db_name}",
|
|
86
|
+
f"--db_user {db_user}",
|
|
87
|
+
f"--db_password {db_password}",
|
|
88
|
+
f"--db_host {db_host}" if db_host else "",
|
|
89
|
+
f"--db_port {db_port}" if db_host else "",
|
|
90
|
+
f"--db-filter=^{db_filter}$",
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
LOGGER.info("Getting Addon Paths")
|
|
94
|
+
|
|
95
|
+
workspace_addons = get_odoo_module_paths(workspace_addon_path)
|
|
96
|
+
if any([re.match(r"( |^)(-i|--init)", i) for i in extra_cmd_args]):
|
|
97
|
+
init_modules = []
|
|
98
|
+
else:
|
|
99
|
+
init_modules = ["base", "web"] if install_base else []
|
|
100
|
+
if install_workspace_modules and workspace_addons:
|
|
101
|
+
init_modules += [f.name for f in workspace_addons]
|
|
102
|
+
init_cmd = "--init " + ",".join(init_modules) if init_modules else ""
|
|
103
|
+
|
|
104
|
+
addon_paths = [str(p.absolute()) for p in addon_paths]
|
|
105
|
+
addon_paths = ", ".join(list(filter(None, addon_paths)))
|
|
106
|
+
|
|
107
|
+
base_cmds = [
|
|
108
|
+
str(odoo_main_path.absolute()) + "/odoo-bin",
|
|
109
|
+
init_cmd,
|
|
110
|
+
f"--config {str(odoo_conf_path.absolute())}",
|
|
111
|
+
"--save",
|
|
112
|
+
f"--load-language {languages}",
|
|
113
|
+
"--stop-after-init",
|
|
114
|
+
f"--addons-path '{addon_paths}'",
|
|
115
|
+
]
|
|
116
|
+
odoo_cmd = base_cmds + db_command
|
|
117
|
+
if extra_cmd_args:
|
|
118
|
+
odoo_cmd += extra_cmd_args
|
|
119
|
+
|
|
120
|
+
_add_default_argument(cmd_list=odoo_cmd, arg="--data-dir", arg_val="/var/lib/odoo")
|
|
121
|
+
|
|
122
|
+
if multithread_worker_count == -1:
|
|
123
|
+
multithread_worker_count = os.cpu_count() or 0 + 1
|
|
124
|
+
|
|
125
|
+
if multithread_worker_count > 0:
|
|
126
|
+
odoo_cmd += [
|
|
127
|
+
"--proxy-mode",
|
|
128
|
+
f"--workers {multithread_worker_count}",
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
odoo_cmd = list(filter(None, odoo_cmd))
|
|
132
|
+
return " ".join(odoo_cmd)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@CLI.unpacker
|
|
136
|
+
@CLI.arg_annotator
|
|
137
|
+
def bootstrap_odoo(
|
|
138
|
+
odoo_main_path=CLI.odoo_paths.bin_path,
|
|
139
|
+
workspace_addon_path=CLI.odoo_paths.workspace_addon_path,
|
|
140
|
+
thirdparty_addon_path=CLI.odoo_paths.thirdparty_addon_path,
|
|
141
|
+
odoo_conf_path=CLI.odoo_paths.conf_path,
|
|
142
|
+
db_filter=CLI.database.db_filter,
|
|
143
|
+
db_host=CLI.database.db_host,
|
|
144
|
+
db_port=CLI.database.db_port,
|
|
145
|
+
db_name=CLI.database.db_name,
|
|
146
|
+
db_user=CLI.database.db_user,
|
|
147
|
+
db_password=CLI.database.db_password,
|
|
148
|
+
extra_cmd_args=CLI.odoo_launch.extra_cmd_args,
|
|
149
|
+
multithread_worker_count=CLI.odoo_launch.multithread_worker_count,
|
|
150
|
+
languages=CLI.odoo_launch.languages,
|
|
151
|
+
no_install_base=CLI.odoo_launch.no_install_base,
|
|
152
|
+
no_install_workspace_modules=CLI.odoo_launch.no_install_workspace_modules,
|
|
153
|
+
):
|
|
154
|
+
"""Bootstrap Odoo."""
|
|
155
|
+
|
|
156
|
+
addon_paths = get_addon_paths(
|
|
157
|
+
odoo_main_repo=odoo_main_path,
|
|
158
|
+
workspace_addon_path=workspace_addon_path,
|
|
159
|
+
thirdparty_addon_path=thirdparty_addon_path,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
cmd_string = _boostrap_command(
|
|
163
|
+
odoo_main_path=odoo_main_path,
|
|
164
|
+
odoo_conf_path=odoo_conf_path,
|
|
165
|
+
workspace_addon_path=workspace_addon_path,
|
|
166
|
+
addon_paths=addon_paths,
|
|
167
|
+
db_host=db_host,
|
|
168
|
+
db_name=db_name,
|
|
169
|
+
db_filter=db_filter,
|
|
170
|
+
db_user=db_user,
|
|
171
|
+
db_password=db_password,
|
|
172
|
+
db_port=db_port,
|
|
173
|
+
extra_cmd_args=extra_cmd_args,
|
|
174
|
+
install_base=not no_install_base,
|
|
175
|
+
install_workspace_modules=not no_install_workspace_modules,
|
|
176
|
+
multithread_worker_count=multithread_worker_count,
|
|
177
|
+
languages=languages,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Always update Pip reqs regardless of --no-update-source
|
|
181
|
+
_install_py_reqs_by_odoo_cmd(addon_paths=addon_paths, odoo_bin_cmd=cmd_string)
|
|
182
|
+
|
|
183
|
+
LOGGER.info("Launching Bootstrap Commandline")
|
|
184
|
+
ret = run_cmd(cmd_string).returncode
|
|
185
|
+
if ret != 0:
|
|
186
|
+
LOGGER.error("Odoo-Bin Returned %d", ret)
|
|
187
|
+
return CLI.returner(ret)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Set odoo.conf variables
|
|
3
|
+
"""
|
|
4
|
+
import logging
|
|
5
|
+
from configparser import ConfigParser
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from ..cli_common import CommonCLI
|
|
12
|
+
|
|
13
|
+
CLI = CommonCLI()
|
|
14
|
+
LOGGER = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@CLI.unpacker
|
|
18
|
+
@CLI.arg_annotator
|
|
19
|
+
def set_odoo_config(
|
|
20
|
+
options: List[str] = typer.Argument(..., help="odoo.conf options by key=value"),
|
|
21
|
+
odoo_conf_path=CLI.odoo_paths.conf_path,
|
|
22
|
+
):
|
|
23
|
+
"""
|
|
24
|
+
Set odoo.conf values.
|
|
25
|
+
"""
|
|
26
|
+
conf_path = Path(odoo_conf_path)
|
|
27
|
+
odoo_conf = ConfigParser()
|
|
28
|
+
odoo_conf.read(conf_path)
|
|
29
|
+
LOGGER.info("Setting Odoo Conf Options for Stage")
|
|
30
|
+
custom_opts = {}
|
|
31
|
+
for op in options:
|
|
32
|
+
if "=" not in op:
|
|
33
|
+
LOGGER.error("Cannot parse Option: '%s' --> missing = sign", op)
|
|
34
|
+
raise ValueError("")
|
|
35
|
+
op_split = op.split("=")
|
|
36
|
+
custom_opts[op_split[0]] = op_split[1]
|
|
37
|
+
LOGGER.debug("Writing Conf Options: %s", custom_opts)
|
|
38
|
+
if "options" not in odoo_conf:
|
|
39
|
+
odoo_conf.add_section("options")
|
|
40
|
+
odoo_conf["options"] = {}
|
|
41
|
+
odoo_conf["options"].update(custom_opts)
|
|
42
|
+
conf_path.touch(exist_ok=True)
|
|
43
|
+
odoo_conf.write(conf_path.open("w"))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .cli import db_cli_app
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from .connection import login_db
|
|
4
|
+
from .passwords import set_passwords
|
|
5
|
+
from .query import query_database
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def db_cli_app():
|
|
9
|
+
app = typer.Typer(
|
|
10
|
+
no_args_is_help=True,
|
|
11
|
+
help="Functions that directly act on the Postgres DB",
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
app.command()(set_passwords)
|
|
15
|
+
app.command("login")(login_db)
|
|
16
|
+
app.command("query")(query_database)
|
|
17
|
+
|
|
18
|
+
return app
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import subprocess
|
|
3
|
+
from contextlib import contextmanager
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
import psycopg2
|
|
7
|
+
|
|
8
|
+
from ...cli_common import CommonCLI
|
|
9
|
+
from ...helpers.system import run_cmd
|
|
10
|
+
|
|
11
|
+
LOGGER = logging.getLogger(__name__)
|
|
12
|
+
CLI = CommonCLI()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@CLI.arg_annotator
|
|
16
|
+
def login_db(
|
|
17
|
+
db_host=CLI.database.db_host,
|
|
18
|
+
db_port=CLI.database.db_port,
|
|
19
|
+
db_name=CLI.database.db_name,
|
|
20
|
+
db_user=CLI.database.db_user,
|
|
21
|
+
db_password=CLI.database.db_password,
|
|
22
|
+
):
|
|
23
|
+
"""Login Interactive psql CLI using provided credentials"""
|
|
24
|
+
command = ["psql", f"-h{db_host}", f"-p{db_port}", f"-U{db_user}", f"-d{db_name}"]
|
|
25
|
+
subprocess.run(command, env={"PGPASSWORD": db_password})
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class DBConnection:
|
|
30
|
+
db_name: str
|
|
31
|
+
hostname: str
|
|
32
|
+
username: str
|
|
33
|
+
password: str
|
|
34
|
+
port: int = 0
|
|
35
|
+
conn_timeout: int = 5
|
|
36
|
+
|
|
37
|
+
def get_connection(self):
|
|
38
|
+
LOGGER.debug(
|
|
39
|
+
"Connecting to DB: '%s:%s' U='%s' P='%s' D='%s'",
|
|
40
|
+
self.hostname,
|
|
41
|
+
self.port,
|
|
42
|
+
self.username,
|
|
43
|
+
self.password,
|
|
44
|
+
self.db_name,
|
|
45
|
+
)
|
|
46
|
+
return psycopg2.connect(
|
|
47
|
+
host=self.hostname,
|
|
48
|
+
port=self.port or None,
|
|
49
|
+
user=self.username,
|
|
50
|
+
password=self.password,
|
|
51
|
+
dbname=self.db_name,
|
|
52
|
+
connect_timeout=self.conn_timeout,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
@contextmanager
|
|
56
|
+
def connect(self):
|
|
57
|
+
connection = self.get_connection()
|
|
58
|
+
cr = connection.cursor()
|
|
59
|
+
try:
|
|
60
|
+
yield cr
|
|
61
|
+
LOGGER.debug("Committing DB cursor")
|
|
62
|
+
connection.commit()
|
|
63
|
+
except Exception as e:
|
|
64
|
+
LOGGER.warning("Rolling Back DB cursor. Got Exception: %s", e)
|
|
65
|
+
connection.rollback()
|
|
66
|
+
raise e
|
|
67
|
+
finally:
|
|
68
|
+
LOGGER.debug("Closing DB connection")
|
|
69
|
+
cr.close()
|
|
70
|
+
connection.close()
|
|
71
|
+
|
|
72
|
+
def run_psql_shell_command(self, command: str, **kwargs):
|
|
73
|
+
"""Run a psql command using the provided credentials. {} in the command will get templated with the connection string"""
|
|
74
|
+
LOGGER.debug("Running PSQL Command: %s", command)
|
|
75
|
+
arg_list = []
|
|
76
|
+
if h := self.hostname:
|
|
77
|
+
arg_list += ["-h", h]
|
|
78
|
+
if p := self.port:
|
|
79
|
+
arg_list += ["-p", p]
|
|
80
|
+
if u := self.username:
|
|
81
|
+
arg_list += ["-U", u]
|
|
82
|
+
if d := self.db_name:
|
|
83
|
+
arg_list += ["-d", d]
|
|
84
|
+
command_env = {}
|
|
85
|
+
if p := self.password:
|
|
86
|
+
command_env["PGPASSWORD"] = p
|
|
87
|
+
|
|
88
|
+
arg_str = " ".join(arg_list)
|
|
89
|
+
if "{}" in command:
|
|
90
|
+
command = command.format(arg_str)
|
|
91
|
+
else:
|
|
92
|
+
command += " " + " ".join(arg_list)
|
|
93
|
+
|
|
94
|
+
return run_cmd(command, env=command_env, **kwargs)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from passlib.context import CryptContext
|
|
5
|
+
|
|
6
|
+
from ...cli_common import CommonCLI
|
|
7
|
+
from ...helpers.cli import check_dangerous_command
|
|
8
|
+
from .connection import DBConnection
|
|
9
|
+
|
|
10
|
+
LOGGER = logging.getLogger(__name__)
|
|
11
|
+
CLI = CommonCLI()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _hash_odoo_password(password: str) -> str:
|
|
15
|
+
"""Hash Password for Odoo
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
password : str
|
|
20
|
+
Password to hash
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
str
|
|
25
|
+
Hashed Password
|
|
26
|
+
"""
|
|
27
|
+
return CryptContext(schemes=["pbkdf2_sha512", "md5_crypt"]).encrypt(password)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@CLI.arg_annotator
|
|
31
|
+
def set_passwords(
|
|
32
|
+
new_password: str = typer.Argument(..., help="Password to set for all users"),
|
|
33
|
+
db_host=CLI.database.db_host,
|
|
34
|
+
db_port=CLI.database.db_port,
|
|
35
|
+
db_name=CLI.database.db_name,
|
|
36
|
+
db_user=CLI.database.db_user,
|
|
37
|
+
db_password=CLI.database.db_password,
|
|
38
|
+
):
|
|
39
|
+
"""Set Login Password for all Users."""
|
|
40
|
+
|
|
41
|
+
check_dangerous_command()
|
|
42
|
+
|
|
43
|
+
connection = DBConnection(
|
|
44
|
+
hostname=db_host,
|
|
45
|
+
port=db_port,
|
|
46
|
+
username=db_user,
|
|
47
|
+
password=db_password,
|
|
48
|
+
db_name=db_name,
|
|
49
|
+
)
|
|
50
|
+
hashed_pw = _hash_odoo_password(new_password)
|
|
51
|
+
with connection.connect() as conn:
|
|
52
|
+
try:
|
|
53
|
+
conn.execute(f"UPDATE res_users SET password='{hashed_pw}'")
|
|
54
|
+
except Exception:
|
|
55
|
+
raise typer.Exit(1)
|
|
56
|
+
LOGGER.info("Password for all users set to: '%s'", new_password)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from ...cli_common import CommonCLI
|
|
6
|
+
from ...helpers.cli import check_dangerous_command
|
|
7
|
+
from .connection import DBConnection
|
|
8
|
+
|
|
9
|
+
LOGGER = logging.getLogger(__name__)
|
|
10
|
+
CLI = CommonCLI()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@CLI.arg_annotator
|
|
14
|
+
def query_database(
|
|
15
|
+
query: str = typer.Argument(..., help="SQL Query"),
|
|
16
|
+
db_host=CLI.database.db_host,
|
|
17
|
+
db_port=CLI.database.db_port,
|
|
18
|
+
db_name=CLI.database.db_name,
|
|
19
|
+
db_user=CLI.database.db_user,
|
|
20
|
+
db_password=CLI.database.db_password,
|
|
21
|
+
):
|
|
22
|
+
"""Run a Query against the database."""
|
|
23
|
+
|
|
24
|
+
check_dangerous_command()
|
|
25
|
+
# regex to check if SQL query contains writing command
|
|
26
|
+
|
|
27
|
+
connection = DBConnection(
|
|
28
|
+
hostname=db_host,
|
|
29
|
+
port=db_port,
|
|
30
|
+
username=db_user,
|
|
31
|
+
password=db_password,
|
|
32
|
+
db_name=db_name,
|
|
33
|
+
)
|
|
34
|
+
with connection.connect() as cursor:
|
|
35
|
+
try:
|
|
36
|
+
cursor.execute(query)
|
|
37
|
+
rows = cursor.fetchall()
|
|
38
|
+
for row in rows:
|
|
39
|
+
print("\t".join(row)) # pylint: disable=print-used
|
|
40
|
+
except Exception:
|
|
41
|
+
raise typer.Exit(1)
|