execsql2 2.16.15__py3-none-any.whl → 2.16.16__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.
- execsql/api.py +4 -0
- execsql/cli/__init__.py +156 -134
- execsql/cli/help.py +10 -1
- execsql/cli/run.py +4 -0
- execsql/config.py +2 -0
- execsql/data/__init__.py +0 -0
- execsql/data/execsql.conf.template +327 -0
- execsql/db/sqlite.py +47 -43
- execsql/metacommands/system.py +10 -9
- execsql2-2.16.16.data/data/execsql2_extras/execsql.conf +327 -0
- {execsql2-2.16.15.dist-info → execsql2-2.16.16.dist-info}/METADATA +1 -1
- {execsql2-2.16.15.dist-info → execsql2-2.16.16.dist-info}/RECORD +30 -28
- execsql2-2.16.15.data/data/execsql2_extras/execsql.conf +0 -287
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/README.md +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/config_settings.sqlite +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/make_config_db.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/md_compare.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/md_glossary.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/md_upsert.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/pg_compare.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/pg_glossary.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/pg_upsert.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/script_template.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/ss_compare.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/ss_glossary.sql +0 -0
- {execsql2-2.16.15.data → execsql2-2.16.16.data}/data/execsql2_extras/ss_upsert.sql +0 -0
- {execsql2-2.16.15.dist-info → execsql2-2.16.16.dist-info}/WHEEL +0 -0
- {execsql2-2.16.15.dist-info → execsql2-2.16.16.dist-info}/entry_points.txt +0 -0
- {execsql2-2.16.15.dist-info → execsql2-2.16.16.dist-info}/licenses/LICENSE.txt +0 -0
- {execsql2-2.16.15.dist-info → execsql2-2.16.16.dist-info}/licenses/NOTICE +0 -0
execsql/api.py
CHANGED
|
@@ -316,6 +316,7 @@ def run(
|
|
|
316
316
|
encoding: str = "utf-8",
|
|
317
317
|
halt_on_error: bool = True,
|
|
318
318
|
new_db: bool = False,
|
|
319
|
+
allow_system_cmd: bool = True,
|
|
319
320
|
) -> ScriptResult:
|
|
320
321
|
"""Execute a SQL script and return the result.
|
|
321
322
|
|
|
@@ -337,6 +338,8 @@ def run(
|
|
|
337
338
|
error. If ``False``, capture errors and continue.
|
|
338
339
|
new_db: If ``True``, create the database if it does not exist
|
|
339
340
|
(SQLite, PostgreSQL, DuckDB).
|
|
341
|
+
allow_system_cmd: If ``False``, the SYSTEM_CMD (SHELL) metacommand
|
|
342
|
+
is disabled and will raise an error if encountered.
|
|
340
343
|
|
|
341
344
|
Returns:
|
|
342
345
|
A :class:`ScriptResult` with execution outcome, timing, errors,
|
|
@@ -434,6 +437,7 @@ def run(
|
|
|
434
437
|
ctx.subvars = subvars
|
|
435
438
|
ctx.status = StatObj()
|
|
436
439
|
ctx.status.halt_on_err = halt_on_error
|
|
440
|
+
conf.allow_system_cmd = allow_system_cmd
|
|
437
441
|
ctx.conf = conf
|
|
438
442
|
|
|
439
443
|
# Capture output to a buffer (suppress stdout/stderr)
|
execsql/cli/__init__.py
CHANGED
|
@@ -20,7 +20,7 @@ import typer
|
|
|
20
20
|
|
|
21
21
|
from execsql import __version__
|
|
22
22
|
from execsql.cli.dsn import _parse_connection_string, _SCHEME_TO_DBTYPE # noqa: F401 — re-export
|
|
23
|
-
from execsql.cli.help import _console, _err_console, _print_encodings, _print_metacommands # noqa: F401 — re-export
|
|
23
|
+
from execsql.cli.help import _console, _err_console, _init_config, _print_encodings, _print_metacommands # noqa: F401 — re-export
|
|
24
24
|
from execsql.cli.run import _connect_initial_db, _run # noqa: F401 — re-export
|
|
25
25
|
from execsql.exceptions import ConfigError, ErrInfo
|
|
26
26
|
|
|
@@ -29,6 +29,7 @@ __all__ = [
|
|
|
29
29
|
"_connect_initial_db",
|
|
30
30
|
"_console",
|
|
31
31
|
"_err_console",
|
|
32
|
+
"_init_config",
|
|
32
33
|
"_legacy_main",
|
|
33
34
|
"_parse_connection_string",
|
|
34
35
|
"_print_encodings",
|
|
@@ -72,28 +73,55 @@ def main(
|
|
|
72
73
|
"name (client-server DBs) or a database file path (file-based DBs)."
|
|
73
74
|
),
|
|
74
75
|
),
|
|
75
|
-
#
|
|
76
|
-
|
|
76
|
+
# -- Connection --------------------------------------------------------
|
|
77
|
+
db_type: str | None = typer.Option(
|
|
77
78
|
None,
|
|
78
|
-
"-
|
|
79
|
-
"--
|
|
80
|
-
metavar="
|
|
81
|
-
help=
|
|
79
|
+
"-t",
|
|
80
|
+
"--type",
|
|
81
|
+
metavar="{a,d,p,s,l,m,k,o,f}",
|
|
82
|
+
help=(
|
|
83
|
+
"Database type: [bold]a[/bold]=MS-Access, [bold]p[/bold]=PostgreSQL, "
|
|
84
|
+
"[bold]s[/bold]=SQL Server, [bold]l[/bold]=SQLite, [bold]m[/bold]=MySQL/MariaDB, "
|
|
85
|
+
"[bold]k[/bold]=DuckDB, [bold]o[/bold]=Oracle, [bold]f[/bold]=Firebird, "
|
|
86
|
+
"[bold]d[/bold]=DSN."
|
|
87
|
+
),
|
|
82
88
|
),
|
|
83
|
-
|
|
89
|
+
dsn: str | None = typer.Option(
|
|
84
90
|
None,
|
|
85
|
-
"
|
|
86
|
-
"--
|
|
87
|
-
metavar="
|
|
88
|
-
help=
|
|
91
|
+
"--dsn",
|
|
92
|
+
"--connection-string",
|
|
93
|
+
metavar="URL",
|
|
94
|
+
help=(
|
|
95
|
+
"Database connection URL, e.g. [cyan]postgresql://user:pass@host:5432/db[/cyan]. "
|
|
96
|
+
"Supported schemes: postgresql, mysql, mssql, oracle, firebird, sqlite, duckdb. "
|
|
97
|
+
"Overrides [cyan]-t[/cyan]/[cyan]-u[/cyan]/[cyan]-p[/cyan] and positional server/db args."
|
|
98
|
+
),
|
|
89
99
|
),
|
|
90
|
-
|
|
100
|
+
user: str | None = typer.Option(
|
|
91
101
|
None,
|
|
92
|
-
"-
|
|
93
|
-
"--
|
|
94
|
-
|
|
95
|
-
help="Auto-create directories for EXPORT metacommand. [dim]n=no (default), y=yes[/dim]",
|
|
102
|
+
"-u",
|
|
103
|
+
"--user",
|
|
104
|
+
help="Database user name.",
|
|
96
105
|
),
|
|
106
|
+
port: int | None = typer.Option(
|
|
107
|
+
None,
|
|
108
|
+
"-p",
|
|
109
|
+
"--port",
|
|
110
|
+
help="Database server port.",
|
|
111
|
+
),
|
|
112
|
+
no_passwd: bool = typer.Option(
|
|
113
|
+
False,
|
|
114
|
+
"-w",
|
|
115
|
+
"--no-passwd",
|
|
116
|
+
help="Skip password prompt when user is specified.",
|
|
117
|
+
),
|
|
118
|
+
new_db: bool = typer.Option(
|
|
119
|
+
False,
|
|
120
|
+
"-n",
|
|
121
|
+
"--new-db",
|
|
122
|
+
help="Create a new SQLite or Postgres database if it does not exist.",
|
|
123
|
+
),
|
|
124
|
+
# -- Encoding ----------------------------------------------------------
|
|
97
125
|
database_encoding: str | None = typer.Option(
|
|
98
126
|
None,
|
|
99
127
|
"-e",
|
|
@@ -118,35 +146,13 @@ def main(
|
|
|
118
146
|
"--import-encoding",
|
|
119
147
|
help="Encoding for data files used with IMPORT.",
|
|
120
148
|
),
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"-l",
|
|
124
|
-
"--user-logfile",
|
|
125
|
-
help="Write a log file to [cyan]~/execsql.log[/cyan].",
|
|
126
|
-
),
|
|
127
|
-
metacommands: bool = typer.Option(
|
|
128
|
-
False,
|
|
129
|
-
"-m",
|
|
130
|
-
"--metacommands",
|
|
131
|
-
help="List metacommands and exit.",
|
|
132
|
-
),
|
|
133
|
-
new_db: bool = typer.Option(
|
|
134
|
-
False,
|
|
135
|
-
"-n",
|
|
136
|
-
"--new-db",
|
|
137
|
-
help="Create a new SQLite or Postgres database if it does not exist.",
|
|
138
|
-
),
|
|
139
|
-
online_help: bool = typer.Option(
|
|
140
|
-
False,
|
|
141
|
-
"-o",
|
|
142
|
-
"--online-help",
|
|
143
|
-
help="Open the online documentation in the default browser.",
|
|
144
|
-
),
|
|
145
|
-
port: int | None = typer.Option(
|
|
149
|
+
# -- Import/Export -----------------------------------------------------
|
|
150
|
+
import_buffer: int | None = typer.Option(
|
|
146
151
|
None,
|
|
147
|
-
"-
|
|
148
|
-
"--
|
|
149
|
-
|
|
152
|
+
"-z",
|
|
153
|
+
"--import-buffer",
|
|
154
|
+
metavar="KB",
|
|
155
|
+
help="Import buffer size in KB. [dim]Default: 32[/dim]",
|
|
150
156
|
),
|
|
151
157
|
scanlines: int | None = typer.Option(
|
|
152
158
|
None,
|
|
@@ -155,59 +161,36 @@ def main(
|
|
|
155
161
|
metavar="N",
|
|
156
162
|
help="Lines to scan for IMPORT format detection. [dim]0 = scan entire file.[/dim]",
|
|
157
163
|
),
|
|
158
|
-
|
|
164
|
+
boolean_int: str | None = typer.Option(
|
|
159
165
|
None,
|
|
160
|
-
"-
|
|
161
|
-
"--
|
|
162
|
-
metavar="{
|
|
163
|
-
help=
|
|
164
|
-
"Database type: [bold]a[/bold]=MS-Access, [bold]p[/bold]=PostgreSQL, "
|
|
165
|
-
"[bold]s[/bold]=SQL Server, [bold]l[/bold]=SQLite, [bold]m[/bold]=MySQL/MariaDB, "
|
|
166
|
-
"[bold]k[/bold]=DuckDB, [bold]o[/bold]=Oracle, [bold]f[/bold]=Firebird, "
|
|
167
|
-
"[bold]d[/bold]=DSN."
|
|
168
|
-
),
|
|
166
|
+
"-b",
|
|
167
|
+
"--boolean-int",
|
|
168
|
+
metavar="{0,1,t,f,y,n}",
|
|
169
|
+
help="Treat integers 0 and 1 as boolean values.",
|
|
169
170
|
),
|
|
170
|
-
|
|
171
|
+
make_dirs: str | None = typer.Option(
|
|
171
172
|
None,
|
|
172
|
-
"-
|
|
173
|
-
"--
|
|
174
|
-
|
|
173
|
+
"-d",
|
|
174
|
+
"--directories",
|
|
175
|
+
metavar="{0,1,t,f,y,n}",
|
|
176
|
+
help="Auto-create directories for EXPORT metacommand. [dim]n=no (default), y=yes[/dim]",
|
|
175
177
|
),
|
|
176
|
-
|
|
178
|
+
output_dir: str | None = typer.Option(
|
|
177
179
|
None,
|
|
178
|
-
"-
|
|
179
|
-
"
|
|
180
|
-
metavar="{0,1,2,3}",
|
|
180
|
+
"--output-dir",
|
|
181
|
+
metavar="DIR",
|
|
181
182
|
help=(
|
|
182
|
-
"
|
|
183
|
-
"
|
|
183
|
+
"Default base directory for EXPORT output files. "
|
|
184
|
+
"Relative paths in EXPORT metacommands are joined to this directory. "
|
|
185
|
+
"Absolute paths and [cyan]stdout[/cyan] are unaffected."
|
|
184
186
|
),
|
|
185
187
|
),
|
|
186
|
-
|
|
187
|
-
None,
|
|
188
|
-
"--gui-framework",
|
|
189
|
-
metavar="{tkinter,textual}",
|
|
190
|
-
help="GUI framework to use with [cyan]--visible-prompts[/cyan]. [dim]Default: tkinter[/dim]",
|
|
191
|
-
),
|
|
192
|
-
no_passwd: bool = typer.Option(
|
|
193
|
-
False,
|
|
194
|
-
"-w",
|
|
195
|
-
"--no-passwd",
|
|
196
|
-
help="Skip password prompt when user is specified.",
|
|
197
|
-
),
|
|
198
|
-
encodings: bool = typer.Option(
|
|
188
|
+
progress: bool = typer.Option(
|
|
199
189
|
False,
|
|
200
|
-
"
|
|
201
|
-
"
|
|
202
|
-
help="List available encoding names and exit.",
|
|
203
|
-
),
|
|
204
|
-
import_buffer: int | None = typer.Option(
|
|
205
|
-
None,
|
|
206
|
-
"-z",
|
|
207
|
-
"--import-buffer",
|
|
208
|
-
metavar="KB",
|
|
209
|
-
help="Import buffer size in KB. [dim]Default: 32[/dim]",
|
|
190
|
+
"--progress",
|
|
191
|
+
help="Show a progress bar for long-running IMPORT operations.",
|
|
210
192
|
),
|
|
193
|
+
# -- Execution ---------------------------------------------------------
|
|
211
194
|
command: str | None = typer.Option(
|
|
212
195
|
None,
|
|
213
196
|
"-c",
|
|
@@ -221,7 +204,7 @@ def main(
|
|
|
221
204
|
dry_run: bool = typer.Option(
|
|
222
205
|
False,
|
|
223
206
|
"--dry-run",
|
|
224
|
-
help=
|
|
207
|
+
help="Parse the script and print the command list without connecting to a database or executing anything.",
|
|
225
208
|
),
|
|
226
209
|
lint: bool = typer.Option(
|
|
227
210
|
False,
|
|
@@ -232,51 +215,23 @@ def main(
|
|
|
232
215
|
"and missing INCLUDE files (warnings). Exits 0 if no errors, 1 if errors found."
|
|
233
216
|
),
|
|
234
217
|
),
|
|
235
|
-
|
|
218
|
+
parse_tree: bool = typer.Option(
|
|
236
219
|
False,
|
|
237
|
-
"--
|
|
238
|
-
help=(
|
|
239
|
-
"Test database connectivity and exit. "
|
|
240
|
-
"Prints connection details and the server version on success (exit 0), "
|
|
241
|
-
"or the error message on failure (exit 1). "
|
|
242
|
-
"No script file is required."
|
|
243
|
-
),
|
|
244
|
-
),
|
|
245
|
-
dsn: str | None = typer.Option(
|
|
246
|
-
None,
|
|
247
|
-
"--dsn",
|
|
248
|
-
"--connection-string",
|
|
249
|
-
metavar="URL",
|
|
250
|
-
help=(
|
|
251
|
-
"Database connection URL, e.g. [cyan]postgresql://user:pass@host:5432/db[/cyan]. "
|
|
252
|
-
"Supported schemes: postgresql, mysql, mssql, oracle, firebird, sqlite, duckdb. "
|
|
253
|
-
"Overrides [cyan]-t[/cyan]/[cyan]-u[/cyan]/[cyan]-p[/cyan] and positional server/db args."
|
|
254
|
-
),
|
|
255
|
-
),
|
|
256
|
-
output_dir: str | None = typer.Option(
|
|
257
|
-
None,
|
|
258
|
-
"--output-dir",
|
|
259
|
-
metavar="DIR",
|
|
220
|
+
"--parse-tree",
|
|
260
221
|
help=(
|
|
261
|
-
"
|
|
262
|
-
"
|
|
263
|
-
"Absolute paths and [cyan]stdout[/cyan] are unaffected."
|
|
222
|
+
"Parse the script into an abstract syntax tree and print the tree structure. "
|
|
223
|
+
"Does not connect to a database or execute anything."
|
|
264
224
|
),
|
|
265
225
|
),
|
|
266
|
-
|
|
267
|
-
False,
|
|
268
|
-
"--progress",
|
|
269
|
-
help="Show a progress bar for long-running IMPORT operations.",
|
|
270
|
-
),
|
|
271
|
-
dump_keywords: bool = typer.Option(
|
|
226
|
+
debug: bool = typer.Option(
|
|
272
227
|
False,
|
|
273
|
-
"--
|
|
274
|
-
help="
|
|
228
|
+
"--debug",
|
|
229
|
+
help="Start in step-through debug mode. The debug REPL pauses before each statement.",
|
|
275
230
|
),
|
|
276
|
-
|
|
231
|
+
no_system_cmd: bool = typer.Option(
|
|
277
232
|
False,
|
|
278
|
-
"--
|
|
279
|
-
help="
|
|
233
|
+
"--no-system-cmd",
|
|
234
|
+
help="Disable the SYSTEM_CMD (SHELL) metacommand. Scripts that use SHELL will fail with an error.",
|
|
280
235
|
),
|
|
281
236
|
profile: bool = typer.Option(
|
|
282
237
|
False,
|
|
@@ -288,6 +243,24 @@ def main(
|
|
|
288
243
|
"--profile-limit",
|
|
289
244
|
help="Number of top statements to show in the --profile timing summary (default: 20).",
|
|
290
245
|
),
|
|
246
|
+
# -- GUI ---------------------------------------------------------------
|
|
247
|
+
use_gui: str | None = typer.Option(
|
|
248
|
+
None,
|
|
249
|
+
"-v",
|
|
250
|
+
"--visible-prompts",
|
|
251
|
+
metavar="{0,1,2,3}",
|
|
252
|
+
help=(
|
|
253
|
+
"GUI level: [bold]0[/bold]=none (default), [bold]1[/bold]=GUI for password/pause, "
|
|
254
|
+
"[bold]2[/bold]=GUI for password/pause + DB selection, [bold]3[/bold]=full GUI console."
|
|
255
|
+
),
|
|
256
|
+
),
|
|
257
|
+
gui_framework: str | None = typer.Option(
|
|
258
|
+
None,
|
|
259
|
+
"--gui-framework",
|
|
260
|
+
metavar="{tkinter,textual}",
|
|
261
|
+
help="GUI framework to use with [cyan]--visible-prompts[/cyan]. [dim]Default: tkinter[/dim]",
|
|
262
|
+
),
|
|
263
|
+
# -- Configuration -----------------------------------------------------
|
|
291
264
|
config_file: str | None = typer.Option(
|
|
292
265
|
None,
|
|
293
266
|
"--config",
|
|
@@ -298,18 +271,62 @@ def main(
|
|
|
298
271
|
"The file may chain additional configs via its [cyan][config][/cyan] section."
|
|
299
272
|
),
|
|
300
273
|
),
|
|
301
|
-
|
|
274
|
+
init_config: bool = typer.Option(
|
|
302
275
|
False,
|
|
303
|
-
"--
|
|
276
|
+
"--init-config",
|
|
277
|
+
help="Print a default [cyan]execsql.conf[/cyan] template to stdout and exit.",
|
|
278
|
+
),
|
|
279
|
+
sub_vars: list[str] | None = typer.Option(
|
|
280
|
+
None,
|
|
281
|
+
"-a",
|
|
282
|
+
"--assign-arg",
|
|
283
|
+
metavar="VALUE",
|
|
284
|
+
help="Define the replacement string for a substitution variable [cyan]\\$ARG_x[/cyan].",
|
|
285
|
+
),
|
|
286
|
+
user_logfile: bool = typer.Option(
|
|
287
|
+
False,
|
|
288
|
+
"-l",
|
|
289
|
+
"--user-logfile",
|
|
290
|
+
help="Write a log file to [cyan]~/execsql.log[/cyan].",
|
|
291
|
+
),
|
|
292
|
+
# -- Information -------------------------------------------------------
|
|
293
|
+
metacommands: bool = typer.Option(
|
|
294
|
+
False,
|
|
295
|
+
"-m",
|
|
296
|
+
"--metacommands",
|
|
297
|
+
help="List metacommands and exit.",
|
|
298
|
+
),
|
|
299
|
+
encodings: bool = typer.Option(
|
|
300
|
+
False,
|
|
301
|
+
"-y",
|
|
302
|
+
"--encodings",
|
|
303
|
+
help="List available encoding names and exit.",
|
|
304
|
+
),
|
|
305
|
+
dump_keywords: bool = typer.Option(
|
|
306
|
+
False,
|
|
307
|
+
"--dump-keywords",
|
|
308
|
+
help="Dump all metacommand keywords as JSON and exit.",
|
|
309
|
+
),
|
|
310
|
+
list_plugins: bool = typer.Option(
|
|
311
|
+
False,
|
|
312
|
+
"--list-plugins",
|
|
313
|
+
help="List all discovered plugins (metacommands, exporters, importers) and exit.",
|
|
314
|
+
),
|
|
315
|
+
ping: bool = typer.Option(
|
|
316
|
+
False,
|
|
317
|
+
"--ping",
|
|
304
318
|
help=(
|
|
305
|
-
"
|
|
306
|
-
"
|
|
319
|
+
"Test database connectivity and exit. "
|
|
320
|
+
"Prints connection details and the server version on success (exit 0), "
|
|
321
|
+
"or the error message on failure (exit 1). "
|
|
322
|
+
"No script file is required."
|
|
307
323
|
),
|
|
308
324
|
),
|
|
309
|
-
|
|
325
|
+
online_help: bool = typer.Option(
|
|
310
326
|
False,
|
|
311
|
-
"
|
|
312
|
-
|
|
327
|
+
"-o",
|
|
328
|
+
"--online-help",
|
|
329
|
+
help="Open the online documentation in the default browser.",
|
|
313
330
|
),
|
|
314
331
|
version: bool | None = typer.Option(
|
|
315
332
|
None,
|
|
@@ -340,6 +357,10 @@ def main(
|
|
|
340
357
|
_print_encodings()
|
|
341
358
|
raise typer.Exit()
|
|
342
359
|
|
|
360
|
+
if init_config:
|
|
361
|
+
_init_config()
|
|
362
|
+
raise typer.Exit()
|
|
363
|
+
|
|
343
364
|
if dump_keywords:
|
|
344
365
|
import json as _json
|
|
345
366
|
|
|
@@ -580,6 +601,7 @@ def main(
|
|
|
580
601
|
ping=ping,
|
|
581
602
|
lint=lint,
|
|
582
603
|
debug=debug,
|
|
604
|
+
no_system_cmd=no_system_cmd,
|
|
583
605
|
config_file=config_file,
|
|
584
606
|
)
|
|
585
607
|
|
execsql/cli/help.py
CHANGED
|
@@ -11,7 +11,7 @@ from encodings.aliases import aliases as codec_dict
|
|
|
11
11
|
from rich.console import Console
|
|
12
12
|
from rich.table import Table
|
|
13
13
|
|
|
14
|
-
__all__ = ["_console", "_err_console", "_print_encodings", "_print_metacommands"]
|
|
14
|
+
__all__ = ["_console", "_err_console", "_init_config", "_print_encodings", "_print_metacommands"]
|
|
15
15
|
|
|
16
16
|
_console = Console()
|
|
17
17
|
_err_console = Console(stderr=True)
|
|
@@ -77,6 +77,15 @@ _SKIP_FROM_DISPATCH = {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
|
|
80
|
+
def _init_config() -> None:
|
|
81
|
+
"""Print the default execsql.conf template to stdout."""
|
|
82
|
+
import importlib.resources
|
|
83
|
+
import sys
|
|
84
|
+
|
|
85
|
+
template = importlib.resources.files("execsql.data").joinpath("execsql.conf.template").read_text(encoding="utf-8")
|
|
86
|
+
sys.stdout.write(template)
|
|
87
|
+
|
|
88
|
+
|
|
80
89
|
def _print_metacommands() -> None:
|
|
81
90
|
"""Print the metacommands table using Rich.
|
|
82
91
|
|
execsql/cli/run.py
CHANGED
|
@@ -532,6 +532,7 @@ def _run(
|
|
|
532
532
|
ping: bool = False,
|
|
533
533
|
lint: bool = False,
|
|
534
534
|
debug: bool = False,
|
|
535
|
+
no_system_cmd: bool = False,
|
|
535
536
|
config_file: str | None = None,
|
|
536
537
|
) -> None:
|
|
537
538
|
"""Initialise state, connect to the database, load the script, and run it.
|
|
@@ -727,6 +728,9 @@ def _run(
|
|
|
727
728
|
if debug:
|
|
728
729
|
_state.step_mode = True
|
|
729
730
|
|
|
731
|
+
if no_system_cmd:
|
|
732
|
+
conf.allow_system_cmd = False
|
|
733
|
+
|
|
730
734
|
if _ast_tree is not None:
|
|
731
735
|
_execute_script_ast(_ast_tree, conf, profile=profile, profile_limit=profile_limit)
|
|
732
736
|
|
execsql/config.py
CHANGED
|
@@ -288,6 +288,7 @@ class ConfigData:
|
|
|
288
288
|
self.include_opt: list = []
|
|
289
289
|
self.export_output_dir: str | None = None
|
|
290
290
|
self.dao_flush_delay_secs = 5.0
|
|
291
|
+
self.allow_system_cmd = True
|
|
291
292
|
self.zip_buffer_mb = 10
|
|
292
293
|
if os.name == "posix":
|
|
293
294
|
sys_config_file = str(Path("/etc") / self.config_file_name)
|
|
@@ -474,6 +475,7 @@ class ConfigData:
|
|
|
474
475
|
self._get_bool(cp, self._CONFIG_SECTION, "log_datavars", "log_datavars")
|
|
475
476
|
self._get_bool(cp, self._CONFIG_SECTION, "log_sql", "log_sql")
|
|
476
477
|
self._get_int(cp, self._CONFIG_SECTION, "max_log_size_mb", "max_log_size_mb")
|
|
478
|
+
self._get_bool(cp, self._CONFIG_SECTION, "allow_system_cmd", "allow_system_cmd")
|
|
477
479
|
# --- [email] ---
|
|
478
480
|
self._get_str(cp, self._EMAIL_SECTION, "host", "smtp_host")
|
|
479
481
|
self._get_int(cp, self._EMAIL_SECTION, "port", "smtp_port")
|
execsql/data/__init__.py
ADDED
|
File without changes
|