execsql2 2.0.1__py3-none-any.whl → 2.1.2__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.
Files changed (90) hide show
  1. execsql/cli.py +322 -108
  2. execsql/config.py +134 -114
  3. execsql/db/access.py +89 -65
  4. execsql/db/base.py +97 -68
  5. execsql/db/dsn.py +45 -29
  6. execsql/db/duckdb.py +4 -5
  7. execsql/db/factory.py +27 -27
  8. execsql/db/firebird.py +30 -18
  9. execsql/db/mysql.py +38 -14
  10. execsql/db/oracle.py +58 -33
  11. execsql/db/postgres.py +68 -28
  12. execsql/db/sqlite.py +36 -27
  13. execsql/db/sqlserver.py +45 -30
  14. execsql/exceptions.py +68 -64
  15. execsql/exporters/__init__.py +1 -1
  16. execsql/exporters/base.py +42 -17
  17. execsql/exporters/delimited.py +60 -59
  18. execsql/exporters/duckdb.py +8 -12
  19. execsql/exporters/feather.py +32 -24
  20. execsql/exporters/html.py +33 -30
  21. execsql/exporters/json.py +18 -17
  22. execsql/exporters/latex.py +11 -13
  23. execsql/exporters/ods.py +50 -46
  24. execsql/exporters/parquet.py +32 -0
  25. execsql/exporters/pretty.py +16 -15
  26. execsql/exporters/raw.py +9 -11
  27. execsql/exporters/sqlite.py +38 -38
  28. execsql/exporters/templates.py +15 -72
  29. execsql/exporters/values.py +13 -12
  30. execsql/exporters/xls.py +26 -26
  31. execsql/exporters/xml.py +12 -12
  32. execsql/exporters/zip.py +0 -3
  33. execsql/gui/__init__.py +2 -2
  34. execsql/gui/console.py +0 -1
  35. execsql/gui/desktop.py +6 -7
  36. execsql/gui/tui.py +8 -14
  37. execsql/importers/base.py +6 -9
  38. execsql/importers/csv.py +10 -17
  39. execsql/importers/feather.py +16 -22
  40. execsql/importers/ods.py +3 -4
  41. execsql/importers/xls.py +5 -6
  42. execsql/metacommands/__init__.py +8 -8
  43. execsql/metacommands/conditions.py +41 -33
  44. execsql/metacommands/connect.py +113 -99
  45. execsql/metacommands/control.py +38 -26
  46. execsql/metacommands/data.py +35 -33
  47. execsql/metacommands/debug.py +13 -9
  48. execsql/metacommands/io.py +288 -229
  49. execsql/metacommands/prompt.py +179 -157
  50. execsql/metacommands/script_ext.py +11 -9
  51. execsql/metacommands/system.py +44 -25
  52. execsql/models.py +9 -16
  53. execsql/parser.py +10 -10
  54. execsql/script.py +183 -157
  55. execsql/state.py +170 -208
  56. execsql/types.py +46 -81
  57. execsql/utils/auth.py +114 -14
  58. execsql/utils/crypto.py +31 -4
  59. execsql/utils/datetime.py +7 -7
  60. execsql/utils/errors.py +34 -29
  61. execsql/utils/fileio.py +90 -55
  62. execsql/utils/gui.py +22 -23
  63. execsql/utils/mail.py +15 -17
  64. execsql/utils/numeric.py +2 -3
  65. execsql/utils/regex.py +9 -12
  66. execsql/utils/strings.py +10 -12
  67. execsql/utils/timer.py +0 -2
  68. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/execsql.conf +1 -1
  69. execsql2-2.1.2.dist-info/METADATA +300 -0
  70. execsql2-2.1.2.dist-info/RECORD +96 -0
  71. execsql2-2.0.1.dist-info/METADATA +0 -406
  72. execsql2-2.0.1.dist-info/RECORD +0 -95
  73. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/READ_ME.rst +0 -0
  74. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/config_settings.sqlite +0 -0
  75. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
  76. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/make_config_db.sql +0 -0
  77. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/md_compare.sql +0 -0
  78. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/md_glossary.sql +0 -0
  79. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/md_upsert.sql +0 -0
  80. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/pg_compare.sql +0 -0
  81. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/pg_glossary.sql +0 -0
  82. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/pg_upsert.sql +0 -0
  83. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/script_template.sql +0 -0
  84. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/ss_compare.sql +0 -0
  85. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/ss_glossary.sql +0 -0
  86. {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/ss_upsert.sql +0 -0
  87. {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/WHEEL +0 -0
  88. {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/entry_points.txt +0 -0
  89. {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/licenses/LICENSE.txt +0 -0
  90. {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/licenses/NOTICE +0 -0
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+ from execsql.db.access import AccessDatabase
2
3
 
3
4
  """
4
5
  Database connection metacommand handlers for execsql.
@@ -19,30 +20,43 @@ database connections at script runtime:
19
20
  - ``x_close_db`` — ``CLOSE DATABASE <alias>``
20
21
  """
21
22
 
23
+ from pathlib import Path
22
24
  from typing import Any
23
25
 
24
26
  import execsql.state as _state
27
+ from execsql.db.dsn import DsnDatabase
28
+ from execsql.db.duckdb import DuckDBDatabase
29
+ from execsql.db.firebird import FirebirdDatabase
30
+ from execsql.db.mysql import MySQLDatabase
31
+ from execsql.db.oracle import OracleDatabase
32
+ from execsql.db.postgres import PostgresDatabase
33
+ from execsql.db.sqlite import SQLiteDatabase
34
+ from execsql.db.sqlserver import SqlServerDatabase
35
+ from execsql.exceptions import ErrInfo
36
+ from execsql.types import dbt_postgres
37
+ from execsql.utils.fileio import check_dir
38
+ from execsql.utils.strings import unquoted2
25
39
 
26
40
 
27
41
  def x_connect_pg(**kwargs: Any) -> None:
28
42
  need_pwd = kwargs["need_pwd"]
29
43
  if need_pwd:
30
- need_pwd = _state.unquoted2(need_pwd).lower() == "true"
44
+ need_pwd = unquoted2(need_pwd).lower() == "true"
31
45
  portno = kwargs["port"]
32
46
  if portno:
33
- portno = int(_state.unquoted2(portno))
34
- server = _state.unquoted2(kwargs["server"])
35
- db_name = _state.unquoted2(kwargs["db_name"])
47
+ portno = int(unquoted2(portno))
48
+ server = unquoted2(kwargs["server"])
49
+ db_name = unquoted2(kwargs["db_name"])
36
50
  user = kwargs["user"]
37
51
  if user:
38
- user = _state.unquoted2(user)
52
+ user = unquoted2(user)
39
53
  mk_new = kwargs["new"]
40
- mk_new = _state.unquoted2(mk_new).lower() == "new" if mk_new else False
54
+ mk_new = unquoted2(mk_new).lower() == "new" if mk_new else False
41
55
  pw = kwargs["password"]
42
56
  enc = kwargs["encoding"]
43
57
  if enc:
44
- enc = _state.unquoted2(enc)
45
- new_db = _state.PostgresDatabase(
58
+ enc = unquoted2(enc)
59
+ new_db = PostgresDatabase(
46
60
  server,
47
61
  db_name,
48
62
  user,
@@ -53,7 +67,7 @@ def x_connect_pg(**kwargs: Any) -> None:
53
67
  password=pw,
54
68
  )
55
69
  else:
56
- new_db = _state.PostgresDatabase(
70
+ new_db = PostgresDatabase(
57
71
  server,
58
72
  db_name,
59
73
  user,
@@ -69,15 +83,15 @@ def x_connect_pg(**kwargs: Any) -> None:
69
83
  def x_connect_user_pg(**kwargs: Any) -> None:
70
84
  portno = kwargs["port"]
71
85
  if portno:
72
- portno = int(_state.unquoted2(portno))
73
- server = _state.unquoted2(kwargs["server"])
74
- db_name = _state.unquoted2(kwargs["db_name"])
86
+ portno = int(unquoted2(portno))
87
+ server = unquoted2(kwargs["server"])
88
+ db_name = unquoted2(kwargs["db_name"])
75
89
  user = _state.dbs.current().user if _state.dbs.current().user else None
76
90
  pw = _state.upass
77
91
  enc = kwargs["encoding"]
78
92
  if enc:
79
- enc = _state.unquoted2(enc)
80
- new_db = _state.PostgresDatabase(
93
+ enc = unquoted2(enc)
94
+ new_db = PostgresDatabase(
81
95
  server,
82
96
  db_name,
83
97
  user,
@@ -88,7 +102,7 @@ def x_connect_user_pg(**kwargs: Any) -> None:
88
102
  password=pw,
89
103
  )
90
104
  else:
91
- new_db = _state.PostgresDatabase(
105
+ new_db = PostgresDatabase(
92
106
  server,
93
107
  db_name,
94
108
  user,
@@ -102,24 +116,24 @@ def x_connect_user_pg(**kwargs: Any) -> None:
102
116
 
103
117
 
104
118
  def x_connect_ssvr(**kwargs: Any) -> None:
105
- server = _state.unquoted2(kwargs["server"])
106
- db_name = _state.unquoted2(kwargs["db_name"])
119
+ server = unquoted2(kwargs["server"])
120
+ db_name = unquoted2(kwargs["db_name"])
107
121
  user = kwargs["user"]
108
122
  if user:
109
- user = _state.unquoted2(user)
123
+ user = unquoted2(user)
110
124
  need_pwd = kwargs["need_pwd"]
111
125
  pw = kwargs["password"]
112
126
  if pw is not None:
113
- pw = _state.unquoted2(pw)
127
+ pw = unquoted2(pw)
114
128
  if need_pwd:
115
- need_pwd = _state.unquoted2(need_pwd).lower() == "true"
129
+ need_pwd = unquoted2(need_pwd).lower() == "true"
116
130
  portno = kwargs["port"]
117
131
  if portno:
118
- portno = int(_state.unquoted2(portno))
132
+ portno = int(unquoted2(portno))
119
133
  encoding = kwargs["encoding"]
120
134
  if encoding:
121
- encoding = _state.unquoted2(encoding)
122
- new_db = _state.SqlServerDatabase(
135
+ encoding = unquoted2(encoding)
136
+ new_db = SqlServerDatabase(
123
137
  server,
124
138
  db_name,
125
139
  user_name=user,
@@ -135,15 +149,15 @@ def x_connect_ssvr(**kwargs: Any) -> None:
135
149
  def x_connect_user_ssvr(**kwargs: Any) -> None:
136
150
  portno = kwargs["port"]
137
151
  if portno:
138
- portno = int(_state.unquoted2(portno))
139
- server = _state.unquoted2(kwargs["server"])
140
- db_name = _state.unquoted2(kwargs["db_name"])
152
+ portno = int(unquoted2(portno))
153
+ server = unquoted2(kwargs["server"])
154
+ db_name = unquoted2(kwargs["db_name"])
141
155
  user = _state.dbs.current().user if _state.dbs.current().user else None
142
156
  pw = _state.upass
143
157
  enc = kwargs["encoding"]
144
158
  if enc:
145
- enc = _state.unquoted2(enc)
146
- new_db = _state.SqlServerDatabase(
159
+ enc = unquoted2(enc)
160
+ new_db = SqlServerDatabase(
147
161
  server,
148
162
  db_name,
149
163
  user,
@@ -153,7 +167,7 @@ def x_connect_user_ssvr(**kwargs: Any) -> None:
153
167
  password=pw,
154
168
  )
155
169
  else:
156
- new_db = _state.SqlServerDatabase(
170
+ new_db = SqlServerDatabase(
157
171
  server,
158
172
  db_name,
159
173
  user_name=user,
@@ -167,24 +181,24 @@ def x_connect_user_ssvr(**kwargs: Any) -> None:
167
181
 
168
182
 
169
183
  def x_connect_mysql(**kwargs: Any) -> None:
170
- server = _state.unquoted2(kwargs["server"])
171
- db_name = _state.unquoted2(kwargs["db_name"])
184
+ server = unquoted2(kwargs["server"])
185
+ db_name = unquoted2(kwargs["db_name"])
172
186
  user = kwargs["user"]
173
187
  if user:
174
- user = _state.unquoted2(user)
188
+ user = unquoted2(user)
175
189
  need_pwd = kwargs["need_pwd"]
176
190
  if need_pwd:
177
- need_pwd = _state.unquoted2(need_pwd).lower() == "true"
191
+ need_pwd = unquoted2(need_pwd).lower() == "true"
178
192
  portno = kwargs["port"]
179
193
  if portno:
180
- portno = int(_state.unquoted2(portno))
194
+ portno = int(unquoted2(portno))
181
195
  pw = kwargs["password"]
182
196
  if pw:
183
- pw = _state.unquoted2(pw)
197
+ pw = unquoted2(pw)
184
198
  enc = kwargs["encoding"]
185
199
  if enc:
186
- enc = _state.unquoted2(enc)
187
- new_db = _state.MySQLDatabase(
200
+ enc = unquoted2(enc)
201
+ new_db = MySQLDatabase(
188
202
  server,
189
203
  db_name,
190
204
  user,
@@ -194,7 +208,7 @@ def x_connect_mysql(**kwargs: Any) -> None:
194
208
  password=pw,
195
209
  )
196
210
  else:
197
- new_db = _state.MySQLDatabase(
211
+ new_db = MySQLDatabase(
198
212
  server,
199
213
  db_name,
200
214
  user,
@@ -209,15 +223,15 @@ def x_connect_mysql(**kwargs: Any) -> None:
209
223
  def x_connect_user_mysql(**kwargs: Any) -> None:
210
224
  portno = kwargs["port"]
211
225
  if portno:
212
- portno = int(_state.unquoted2(portno))
213
- server = _state.unquoted2(kwargs["server"])
214
- db_name = _state.unquoted2(kwargs["db_name"])
226
+ portno = int(unquoted2(portno))
227
+ server = unquoted2(kwargs["server"])
228
+ db_name = unquoted2(kwargs["db_name"])
215
229
  user = _state.dbs.current().user if _state.dbs.current().user else None
216
230
  pw = _state.upass
217
231
  enc = kwargs["encoding"]
218
232
  if enc:
219
- enc = _state.unquoted2(enc)
220
- new_db = _state.MySQLDatabase(
233
+ enc = unquoted2(enc)
234
+ new_db = MySQLDatabase(
221
235
  server,
222
236
  db_name,
223
237
  user,
@@ -227,7 +241,7 @@ def x_connect_user_mysql(**kwargs: Any) -> None:
227
241
  password=pw,
228
242
  )
229
243
  else:
230
- new_db = _state.MySQLDatabase(
244
+ new_db = MySQLDatabase(
231
245
  server,
232
246
  db_name,
233
247
  user,
@@ -240,39 +254,39 @@ def x_connect_user_mysql(**kwargs: Any) -> None:
240
254
 
241
255
 
242
256
  def x_connect_access(**kwargs: Any) -> None:
243
- db_file = _state.unquoted2(kwargs["filename"])
257
+ db_file = unquoted2(kwargs["filename"])
244
258
  enc = kwargs["encoding"]
245
259
  if enc:
246
- enc = _state.unquoted2(enc)
260
+ enc = unquoted2(enc)
247
261
  need_pwd = kwargs["need_pwd"]
248
262
  password = kwargs["password"]
249
263
  if password:
250
- password = _state.unquoted2(password)
264
+ password = unquoted2(password)
251
265
  if need_pwd:
252
- need_pwd = _state.unquoted2(need_pwd).lower() == "true"
253
- new_db = _state.AccessDatabase(db_file, need_passwd=need_pwd, encoding=enc, password=password)
266
+ need_pwd = unquoted2(need_pwd).lower() == "true"
267
+ new_db = AccessDatabase(db_file, need_passwd=need_pwd, encoding=enc, password=password)
254
268
  _state.dbs.add(kwargs["db_alias"].lower(), new_db)
255
269
  return None
256
270
 
257
271
 
258
272
  def x_connect_fb(**kwargs: Any) -> None:
259
- server = _state.unquoted2(kwargs["server"])
260
- db_name = _state.unquoted2(kwargs["db_name"])
273
+ server = unquoted2(kwargs["server"])
274
+ db_name = unquoted2(kwargs["db_name"])
261
275
  user = kwargs["user"]
262
276
  if user:
263
- user = _state.unquoted2(user)
277
+ user = unquoted2(user)
264
278
  need_pwd = kwargs["need_pwd"]
265
279
  if need_pwd:
266
- need_pwd = _state.unquoted2(need_pwd).lower() == "true"
280
+ need_pwd = unquoted2(need_pwd).lower() == "true"
267
281
  portno = kwargs["port"]
268
282
  if portno:
269
- portno = int(_state.unquoted2(portno))
283
+ portno = int(unquoted2(portno))
270
284
  enc = kwargs["encoding"]
271
285
  if enc:
272
- enc = _state.unquoted2(enc)
273
- new_db = _state.FirebirdDatabase(server, db_name, user, need_passwd=need_pwd, port=portno, encoding=enc)
286
+ enc = unquoted2(enc)
287
+ new_db = FirebirdDatabase(server, db_name, user, need_passwd=need_pwd, port=portno, encoding=enc)
274
288
  else:
275
- new_db = _state.FirebirdDatabase(server, db_name, user, need_passwd=need_pwd, port=portno)
289
+ new_db = FirebirdDatabase(server, db_name, user, need_passwd=need_pwd, port=portno)
276
290
  _state.dbs.add(kwargs["db_alias"].lower(), new_db)
277
291
  return None
278
292
 
@@ -280,40 +294,40 @@ def x_connect_fb(**kwargs: Any) -> None:
280
294
  def x_connect_user_fb(**kwargs: Any) -> None:
281
295
  portno = kwargs["port"]
282
296
  if portno:
283
- portno = int(_state.unquoted2(portno))
284
- server = _state.unquoted2(kwargs["server"])
285
- db_name = _state.unquoted2(kwargs["db_name"])
297
+ portno = int(unquoted2(portno))
298
+ server = unquoted2(kwargs["server"])
299
+ db_name = unquoted2(kwargs["db_name"])
286
300
  user = _state.dbs.current().user if _state.dbs.current().user else None
287
301
  pw = _state.upass
288
302
  enc = kwargs["encoding"]
289
303
  if enc:
290
- enc = _state.unquoted2(enc)
291
- new_db = _state.FirebirdDatabase(server, db_name, user, need_passwd=pw is not None, port=portno, encoding=enc)
304
+ enc = unquoted2(enc)
305
+ new_db = FirebirdDatabase(server, db_name, user, need_passwd=pw is not None, port=portno, encoding=enc)
292
306
  else:
293
- new_db = _state.FirebirdDatabase(server, db_name, user, need_passwd=pw is not None, port=portno)
307
+ new_db = FirebirdDatabase(server, db_name, user, need_passwd=pw is not None, port=portno)
294
308
  _state.dbs.add(kwargs["db_alias"].lower(), new_db)
295
309
  return None
296
310
 
297
311
 
298
312
  def x_connect_ora(**kwargs: Any) -> None:
299
- server = _state.unquoted2(kwargs["server"])
300
- db_name = _state.unquoted2(kwargs["db_name"])
313
+ server = unquoted2(kwargs["server"])
314
+ db_name = unquoted2(kwargs["db_name"])
301
315
  user = kwargs["user"]
302
316
  if user:
303
- user = _state.unquoted2(user)
317
+ user = unquoted2(user)
304
318
  need_pwd = kwargs["need_pwd"]
305
319
  if need_pwd:
306
- need_pwd = _state.unquoted2(need_pwd).lower() == "true"
320
+ need_pwd = unquoted2(need_pwd).lower() == "true"
307
321
  portno = kwargs["port"]
308
322
  if portno:
309
- portno = int(_state.unquoted2(portno))
323
+ portno = int(unquoted2(portno))
310
324
  pw = kwargs["password"]
311
325
  if pw:
312
- pw = _state.unquoted2(pw)
326
+ pw = unquoted2(pw)
313
327
  enc = kwargs["encoding"]
314
328
  if enc:
315
- enc = _state.unquoted2(enc)
316
- new_db = _state.OracleDatabase(
329
+ enc = unquoted2(enc)
330
+ new_db = OracleDatabase(
317
331
  server,
318
332
  db_name,
319
333
  user,
@@ -323,7 +337,7 @@ def x_connect_ora(**kwargs: Any) -> None:
323
337
  password=pw,
324
338
  )
325
339
  else:
326
- new_db = _state.OracleDatabase(server, db_name, user, need_passwd=need_pwd, port=portno, password=pw)
340
+ new_db = OracleDatabase(server, db_name, user, need_passwd=need_pwd, port=portno, password=pw)
327
341
  _state.dbs.add(kwargs["db_alias"].lower(), new_db)
328
342
  return None
329
343
 
@@ -331,15 +345,15 @@ def x_connect_ora(**kwargs: Any) -> None:
331
345
  def x_connect_user_ora(**kwargs: Any) -> None:
332
346
  portno = kwargs["port"]
333
347
  if portno:
334
- portno = int(_state.unquoted2(portno))
335
- server = _state.unquoted2(kwargs["server"])
336
- db_name = _state.unquoted2(kwargs["db_name"])
348
+ portno = int(unquoted2(portno))
349
+ server = unquoted2(kwargs["server"])
350
+ db_name = unquoted2(kwargs["db_name"])
337
351
  user = _state.dbs.current().user if _state.dbs.current().user else None
338
352
  pw = _state.upass
339
353
  enc = kwargs["encoding"]
340
354
  if enc:
341
- enc = _state.unquoted2(enc)
342
- new_db = _state.OracleDatabase(
355
+ enc = unquoted2(enc)
356
+ new_db = OracleDatabase(
343
357
  server,
344
358
  db_name,
345
359
  user,
@@ -349,7 +363,7 @@ def x_connect_user_ora(**kwargs: Any) -> None:
349
363
  password=pw,
350
364
  )
351
365
  else:
352
- new_db = _state.OracleDatabase(
366
+ new_db = OracleDatabase(
353
367
  server,
354
368
  db_name,
355
369
  user,
@@ -364,20 +378,20 @@ def x_connect_user_ora(**kwargs: Any) -> None:
364
378
  def x_connect_duckdb(**kwargs: Any) -> None:
365
379
  import os
366
380
 
367
- db_file = _state.unquoted2(kwargs["filename"])
381
+ db_file = unquoted2(kwargs["filename"])
368
382
  mk_new = kwargs["new"]
369
- mk_new = _state.unquoted2(mk_new).lower() == "new" if mk_new else False
370
- if not mk_new and not os.path.exists(db_file):
371
- raise _state.ErrInfo(
383
+ mk_new = unquoted2(mk_new).lower() == "new" if mk_new else False
384
+ if not mk_new and not Path(db_file).exists():
385
+ raise ErrInfo(
372
386
  type="cmd",
373
387
  command_text=kwargs["metacommandline"],
374
388
  other_msg="DuckDB file does not exist.",
375
389
  )
376
390
  if mk_new:
377
- _state.check_dir(db_file)
378
- if os.path.exists(db_file):
391
+ check_dir(db_file)
392
+ if Path(db_file).exists():
379
393
  os.unlink(db_file)
380
- new_db = _state.DuckDBDatabase(db_file)
394
+ new_db = DuckDBDatabase(db_file)
381
395
  _state.dbs.add(kwargs["db_alias"].lower(), new_db)
382
396
  return None
383
397
 
@@ -385,20 +399,20 @@ def x_connect_duckdb(**kwargs: Any) -> None:
385
399
  def x_connect_sqlite(**kwargs: Any) -> None:
386
400
  import os
387
401
 
388
- db_file = _state.unquoted2(kwargs["filename"])
402
+ db_file = unquoted2(kwargs["filename"])
389
403
  mk_new = kwargs["new"]
390
- mk_new = _state.unquoted2(mk_new).lower() == "new" if mk_new else False
391
- if not mk_new and not os.path.exists(db_file):
392
- raise _state.ErrInfo(
404
+ mk_new = unquoted2(mk_new).lower() == "new" if mk_new else False
405
+ if not mk_new and not Path(db_file).exists():
406
+ raise ErrInfo(
393
407
  type="cmd",
394
408
  command_text=kwargs["metacommandline"],
395
409
  other_msg="SQLite file does not exist.",
396
410
  )
397
411
  if mk_new:
398
- _state.check_dir(db_file)
399
- if os.path.exists(db_file):
412
+ check_dir(db_file)
413
+ if Path(db_file).exists():
400
414
  os.unlink(db_file)
401
- new_db = _state.SQLiteDatabase(db_file)
415
+ new_db = SQLiteDatabase(db_file)
402
416
  _state.dbs.add(kwargs["db_alias"].lower(), new_db)
403
417
  return None
404
418
 
@@ -410,9 +424,9 @@ def x_connect_dsn(**kwargs: Any) -> None:
410
424
  pw = kwargs["password"]
411
425
  enc = kwargs["encoding"]
412
426
  if enc:
413
- new_db = _state.DsnDatabase(kwargs["dsn"], kwargs["user"], need_passwd=need_pwd, encoding=enc, password=pw)
427
+ new_db = DsnDatabase(kwargs["dsn"], kwargs["user"], need_passwd=need_pwd, encoding=enc, password=pw)
414
428
  else:
415
- new_db = _state.DsnDatabase(kwargs["dsn"], kwargs["user"], need_passwd=need_pwd, password=pw)
429
+ new_db = DsnDatabase(kwargs["dsn"], kwargs["user"], need_passwd=need_pwd, password=pw)
416
430
  _state.dbs.add(kwargs["db_alias"].lower(), new_db)
417
431
  return None
418
432
 
@@ -420,7 +434,7 @@ def x_connect_dsn(**kwargs: Any) -> None:
420
434
  def x_use(**kwargs: Any) -> None:
421
435
  db_alias = kwargs["db_alias"].lower()
422
436
  if db_alias not in _state.dbs.aliases():
423
- raise _state.ErrInfo(
437
+ raise ErrInfo(
424
438
  type="cmd",
425
439
  command_text=kwargs["metacommandline"],
426
440
  other_msg=f"Unrecognized database alias: {db_alias}.",
@@ -439,9 +453,9 @@ def x_disconnect(**kwargs: Any) -> None:
439
453
  if alias is None:
440
454
  alias = _state.dbs.current_alias()
441
455
  if alias.lower() == "initial":
442
- raise _state.ErrInfo(type="error", other_msg="You may not disconnect from the initial database used.")
456
+ raise ErrInfo(type="error", other_msg="You may not disconnect from the initial database used.")
443
457
  if _state.status.batch.uses_db(alias):
444
- raise _state.ErrInfo(
458
+ raise ErrInfo(
445
459
  type="error",
446
460
  other_msg="You may not disconnect from a database that is currently used in a batch.",
447
461
  )
@@ -471,7 +485,7 @@ def x_autocommit_off(**kwargs: Any) -> None:
471
485
 
472
486
  def x_pg_vacuum(**kwargs: Any) -> None:
473
487
  db = _state.dbs.current()
474
- if db.type == _state.dbt_postgres:
488
+ if db.type == dbt_postgres:
475
489
  args = kwargs["vacuum_args"]
476
490
  db.vacuum(args)
477
491
 
@@ -479,5 +493,5 @@ def x_pg_vacuum(**kwargs: Any) -> None:
479
493
  def x_daoflushdelay(**kwargs: Any) -> None:
480
494
  delay = float(kwargs["secs"])
481
495
  if delay < 5.0:
482
- raise _state.ErrInfo(type="error", other_msg=f"Invalid DAO flush delay: {delay}; must be >= 5.0.")
496
+ raise ErrInfo(type="error", other_msg=f"Invalid DAO flush delay: {delay}; must be >= 5.0.")
483
497
  _state.conf.dao_flush_delay_secs = delay
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+ from execsql.exceptions import ErrInfo
2
3
 
3
4
  """
4
5
  Control-flow metacommand handlers for execsql.
@@ -20,15 +21,26 @@ import time
20
21
  from typing import Any
21
22
 
22
23
  import execsql.state as _state
24
+ from execsql.script import (
25
+ CommandList,
26
+ CommandListUntilLoop,
27
+ CommandListWhileLoop,
28
+ MetacommandStmt,
29
+ ScriptCmd,
30
+ current_script_line,
31
+ )
32
+ from execsql.utils.errors import exit_now, write_warning
33
+ from execsql.utils.fileio import EncodedFile, check_dir
34
+ from execsql.utils.gui import GUI_HALT, GuiSpec, enable_gui, gui_console_isrunning
23
35
 
24
36
 
25
37
  def x_if(**kwargs: Any) -> None:
26
38
  tf_value = _state.xcmd_test(kwargs["condtest"])
27
39
  if tf_value:
28
- src, line_no = _state.current_script_line()
29
- metacmd = _state.MetacommandStmt(kwargs["condcmd"])
30
- script_cmd = _state.ScriptCmd(src, line_no, "cmd", metacmd)
31
- cmdlist = _state.CommandList([script_cmd], f"{src}_{line_no}")
40
+ src, line_no = current_script_line()
41
+ metacmd = MetacommandStmt(kwargs["condcmd"])
42
+ script_cmd = ScriptCmd(src, line_no, "cmd", metacmd)
43
+ cmdlist = CommandList([script_cmd], f"{src}_{line_no}")
32
44
  _state.commandliststack.append(cmdlist)
33
45
  return None
34
46
 
@@ -81,17 +93,17 @@ def x_loop(**kwargs: Any) -> None:
81
93
  listname = "loop" + str(len(_state.loopcommandstack) + 1)
82
94
  if looptype == "WHILE":
83
95
  _state.loopcommandstack.append(
84
- _state.CommandListWhileLoop([], listname, paramnames=None, loopcondition=loopcond),
96
+ CommandListWhileLoop([], listname, paramnames=None, loopcondition=loopcond),
85
97
  )
86
98
  else:
87
99
  _state.loopcommandstack.append(
88
- _state.CommandListUntilLoop([], listname, paramnames=None, loopcondition=loopcond),
100
+ CommandListUntilLoop([], listname, paramnames=None, loopcondition=loopcond),
89
101
  )
90
102
 
91
103
 
92
104
  def endloop() -> None:
93
105
  if len(_state.loopcommandstack) == 0:
94
- raise _state.ErrInfo("error", other_msg="END LOOP metacommand without a matching preceding LOOP metacommand.")
106
+ raise ErrInfo("error", other_msg="END LOOP metacommand without a matching preceding LOOP metacommand.")
95
107
  _state.compiling_loop = False
96
108
  _state.commandliststack.append(_state.loopcommandstack[-1])
97
109
  _state.loopcommandstack.pop()
@@ -100,18 +112,18 @@ def endloop() -> None:
100
112
  def x_halt(**kwargs: Any) -> None:
101
113
  errmsg = kwargs["errmsg"]
102
114
  tee = kwargs["tee"]
103
- tee = False if not tee else True
115
+ tee = bool(tee)
104
116
  outf = kwargs["filename"]
105
117
  errlevel = kwargs["errorlevel"]
106
118
  conf = _state.conf
107
119
  if outf:
108
- _state.check_dir(outf)
109
- of = _state.EncodedFile(outf, conf.output_encoding).open("a")
120
+ check_dir(outf)
121
+ of = EncodedFile(outf, conf.output_encoding).open("a")
110
122
  of.write(f"{errmsg}\n")
111
123
  of.close()
112
124
  if conf.tee_write_log:
113
125
  _state.exec_log.log_user_msg(errmsg)
114
- use_gui = _state.gui_console_isrunning()
126
+ use_gui = gui_console_isrunning()
115
127
  if errmsg and (use_gui or conf.gui_level > 1):
116
128
  x_halt_msg(table=None, schema=None, **kwargs)
117
129
  return
@@ -121,15 +133,15 @@ def x_halt(**kwargs: Any) -> None:
121
133
  errlevel = 3
122
134
  if errmsg:
123
135
  _state.output.write_err(errmsg)
124
- script, lno = _state.current_script_line()
136
+ script, lno = current_script_line()
125
137
  _state.exec_log.log_exit_halt(script, lno, msg=errmsg)
126
- _state.exit_now(errlevel, None)
138
+ exit_now(errlevel, None)
127
139
 
128
140
 
129
141
  def x_error_halt(**kwargs: Any) -> None:
130
142
  flag = kwargs["onoff"].lower()
131
143
  if flag not in ("on", "off", "yes", "no", "true", "false"):
132
- raise _state.ErrInfo(
144
+ raise ErrInfo(
133
145
  type="cmd",
134
146
  command_text=kwargs["metacommandline"],
135
147
  other_msg=f"Unrecognized flag for error handling: {flag}",
@@ -141,7 +153,7 @@ def x_error_halt(**kwargs: Any) -> None:
141
153
  def x_metacommand_error_halt(**kwargs: Any) -> None:
142
154
  flag = kwargs["onoff"].lower()
143
155
  if flag not in ("on", "off", "yes", "no", "true", "false"):
144
- raise _state.ErrInfo(
156
+ raise ErrInfo(
145
157
  type="cmd",
146
158
  command_text=kwargs["metacommandline"],
147
159
  other_msg=f"Unrecognized flag for metacommand error handling: {flag}",
@@ -166,8 +178,8 @@ def x_rollback(**kwargs: Any) -> None:
166
178
 
167
179
  def x_break(**kwargs: Any) -> None:
168
180
  if len(_state.commandliststack) == 1:
169
- src, line_no = _state.current_script_line()
170
- _state.write_warning(f"BREAK metacommand with no command nesting on line {line_no} of {src}")
181
+ src, line_no = current_script_line()
182
+ write_warning(f"BREAK metacommand with no command nesting on line {line_no} of {src}")
171
183
  else:
172
184
  _state.if_stack.if_levels = _state.if_stack.if_levels[: _state.commandliststack[-1].init_if_level]
173
185
  _state.commandliststack.pop()
@@ -183,10 +195,10 @@ def x_wait_until(**kwargs: Any) -> None:
183
195
  countdown -= 1
184
196
  if kwargs["end"].lower() == "halt":
185
197
  _state.exec_log.log_exit_halt(
186
- *_state.current_script_line(),
198
+ *current_script_line(),
187
199
  msg="Halted at expiration of WAIT_UNTIL metacommand.",
188
200
  )
189
- _state.exit_now(2, None)
201
+ exit_now(2, None)
190
202
  return None
191
203
 
192
204
 
@@ -196,7 +208,7 @@ def x_halt_msg(**kwargs: Any) -> None:
196
208
 
197
209
  errmsg = kwargs["errmsg"]
198
210
  tee = kwargs["tee"]
199
- tee = False if not tee else True
211
+ tee = bool(tee)
200
212
  outf = kwargs["filename"]
201
213
  errlevel = kwargs["errorlevel"]
202
214
  if errlevel:
@@ -205,8 +217,8 @@ def x_halt_msg(**kwargs: Any) -> None:
205
217
  errlevel = 3
206
218
  conf = _state.conf
207
219
  if outf:
208
- _state.check_dir(outf)
209
- of = _state.EncodedFile(outf, conf.output_encoding).open("a")
220
+ check_dir(outf)
221
+ of = EncodedFile(outf, conf.output_encoding).open("a")
210
222
  of.write(f"{errmsg}\n")
211
223
  of.close()
212
224
  schema = kwargs.get("schema")
@@ -218,7 +230,7 @@ def x_halt_msg(**kwargs: Any) -> None:
218
230
  headers, rows = db.select_data(sql)
219
231
  else:
220
232
  headers, rows = None, None
221
- _state.enable_gui()
233
+ enable_gui()
222
234
  return_queue = _queue.Queue()
223
235
  gui_args = {
224
236
  "title": "HALT",
@@ -229,7 +241,7 @@ def x_halt_msg(**kwargs: Any) -> None:
229
241
  "rowset": rows,
230
242
  "help_url": None,
231
243
  }
232
- _state.gui_manager_queue.put(_state.GuiSpec(_state.GUI_HALT, gui_args, return_queue))
244
+ _state.gui_manager_queue.put(GuiSpec(GUI_HALT, gui_args, return_queue))
233
245
  return_queue.get(block=True)
234
- _state.exec_log.log_exit_halt(*_state.current_script_line(), msg=errmsg)
235
- _state.exit_now(errlevel, None)
246
+ _state.exec_log.log_exit_halt(*current_script_line(), msg=errmsg)
247
+ exit_now(errlevel, None)