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.
- execsql/cli.py +322 -108
- execsql/config.py +134 -114
- execsql/db/access.py +89 -65
- execsql/db/base.py +97 -68
- execsql/db/dsn.py +45 -29
- execsql/db/duckdb.py +4 -5
- execsql/db/factory.py +27 -27
- execsql/db/firebird.py +30 -18
- execsql/db/mysql.py +38 -14
- execsql/db/oracle.py +58 -33
- execsql/db/postgres.py +68 -28
- execsql/db/sqlite.py +36 -27
- execsql/db/sqlserver.py +45 -30
- execsql/exceptions.py +68 -64
- execsql/exporters/__init__.py +1 -1
- execsql/exporters/base.py +42 -17
- execsql/exporters/delimited.py +60 -59
- execsql/exporters/duckdb.py +8 -12
- execsql/exporters/feather.py +32 -24
- execsql/exporters/html.py +33 -30
- execsql/exporters/json.py +18 -17
- execsql/exporters/latex.py +11 -13
- execsql/exporters/ods.py +50 -46
- execsql/exporters/parquet.py +32 -0
- execsql/exporters/pretty.py +16 -15
- execsql/exporters/raw.py +9 -11
- execsql/exporters/sqlite.py +38 -38
- execsql/exporters/templates.py +15 -72
- execsql/exporters/values.py +13 -12
- execsql/exporters/xls.py +26 -26
- execsql/exporters/xml.py +12 -12
- execsql/exporters/zip.py +0 -3
- execsql/gui/__init__.py +2 -2
- execsql/gui/console.py +0 -1
- execsql/gui/desktop.py +6 -7
- execsql/gui/tui.py +8 -14
- execsql/importers/base.py +6 -9
- execsql/importers/csv.py +10 -17
- execsql/importers/feather.py +16 -22
- execsql/importers/ods.py +3 -4
- execsql/importers/xls.py +5 -6
- execsql/metacommands/__init__.py +8 -8
- execsql/metacommands/conditions.py +41 -33
- execsql/metacommands/connect.py +113 -99
- execsql/metacommands/control.py +38 -26
- execsql/metacommands/data.py +35 -33
- execsql/metacommands/debug.py +13 -9
- execsql/metacommands/io.py +288 -229
- execsql/metacommands/prompt.py +179 -157
- execsql/metacommands/script_ext.py +11 -9
- execsql/metacommands/system.py +44 -25
- execsql/models.py +9 -16
- execsql/parser.py +10 -10
- execsql/script.py +183 -157
- execsql/state.py +170 -208
- execsql/types.py +46 -81
- execsql/utils/auth.py +114 -14
- execsql/utils/crypto.py +31 -4
- execsql/utils/datetime.py +7 -7
- execsql/utils/errors.py +34 -29
- execsql/utils/fileio.py +90 -55
- execsql/utils/gui.py +22 -23
- execsql/utils/mail.py +15 -17
- execsql/utils/numeric.py +2 -3
- execsql/utils/regex.py +9 -12
- execsql/utils/strings.py +10 -12
- execsql/utils/timer.py +0 -2
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/execsql.conf +1 -1
- execsql2-2.1.2.dist-info/METADATA +300 -0
- execsql2-2.1.2.dist-info/RECORD +96 -0
- execsql2-2.0.1.dist-info/METADATA +0 -406
- execsql2-2.0.1.dist-info/RECORD +0 -95
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/READ_ME.rst +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/config_settings.sqlite +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/make_config_db.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/md_compare.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/md_glossary.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/md_upsert.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/pg_compare.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/pg_glossary.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/pg_upsert.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/script_template.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/ss_compare.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/ss_glossary.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/ss_upsert.sql +0 -0
- {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/WHEEL +0 -0
- {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/entry_points.txt +0 -0
- {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/licenses/LICENSE.txt +0 -0
- {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/licenses/NOTICE +0 -0
execsql/config.py
CHANGED
|
@@ -16,10 +16,9 @@ Provides three classes:
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
import os
|
|
19
|
-
import os.path
|
|
20
|
-
import re
|
|
21
19
|
import sys
|
|
22
20
|
from configparser import ConfigParser
|
|
21
|
+
from pathlib import Path
|
|
23
22
|
|
|
24
23
|
from execsql.exceptions import ConfigError
|
|
25
24
|
from execsql.utils.crypto import Encrypt
|
|
@@ -63,6 +62,7 @@ class ConfigData:
|
|
|
63
62
|
self.username = None
|
|
64
63
|
self.access_username = None
|
|
65
64
|
self.passwd_prompt = True
|
|
65
|
+
self.use_keyring = True
|
|
66
66
|
self.db_file = None
|
|
67
67
|
self.new_db = False
|
|
68
68
|
self.user_logfile = False
|
|
@@ -105,10 +105,12 @@ class ConfigData:
|
|
|
105
105
|
self.outfile_open_timeout = 600
|
|
106
106
|
self.quote_all_text = False
|
|
107
107
|
self.import_row_buffer = 1000
|
|
108
|
+
self.import_progress_interval = 0
|
|
108
109
|
self.export_row_buffer = 1000
|
|
109
110
|
self.template_processor = None
|
|
110
111
|
self.tee_write_log = False
|
|
111
112
|
self.log_datavars = True
|
|
113
|
+
self.max_log_size_mb = 0
|
|
112
114
|
self.smtp_host = None
|
|
113
115
|
self.smtp_port = None
|
|
114
116
|
self.smtp_username = None
|
|
@@ -122,20 +124,20 @@ class ConfigData:
|
|
|
122
124
|
self.dao_flush_delay_secs = 5.0
|
|
123
125
|
self.zip_buffer_mb = 10
|
|
124
126
|
if os.name == "posix":
|
|
125
|
-
sys_config_file =
|
|
127
|
+
sys_config_file = str(Path("/etc") / self.config_file_name)
|
|
126
128
|
else:
|
|
127
|
-
sys_config_file =
|
|
128
|
-
current_script =
|
|
129
|
-
user_config_file =
|
|
130
|
-
script_config_file =
|
|
131
|
-
startdir_config_file =
|
|
129
|
+
sys_config_file = str(Path(os.path.expandvars(r"%APPDATA%")) / self.config_file_name)
|
|
130
|
+
current_script = str(Path(sys.argv[0]).resolve())
|
|
131
|
+
user_config_file = str(Path("~/.config").expanduser() / self.config_file_name)
|
|
132
|
+
script_config_file = str(Path(script_path) / self.config_file_name)
|
|
133
|
+
startdir_config_file = str(Path(".").resolve() / self.config_file_name)
|
|
132
134
|
if startdir_config_file != script_config_file:
|
|
133
135
|
config_files = [sys_config_file, user_config_file, script_config_file, startdir_config_file]
|
|
134
136
|
else:
|
|
135
137
|
config_files = [sys_config_file, user_config_file, startdir_config_file]
|
|
136
138
|
self.files_read: list = []
|
|
137
139
|
for ix, configfile in enumerate(config_files):
|
|
138
|
-
if configfile not in self.files_read and
|
|
140
|
+
if configfile not in self.files_read and Path(configfile).is_file():
|
|
139
141
|
self.files_read.append(configfile)
|
|
140
142
|
cp = ConfigParser()
|
|
141
143
|
cp.read(configfile)
|
|
@@ -155,8 +157,8 @@ class ConfigData:
|
|
|
155
157
|
if cp.has_option(self._CONNECT_SECTION, "port"):
|
|
156
158
|
try:
|
|
157
159
|
self.port = cp.getint(self._CONNECT_SECTION, "port")
|
|
158
|
-
except Exception:
|
|
159
|
-
raise ConfigError("Invalid port number.")
|
|
160
|
+
except Exception as e:
|
|
161
|
+
raise ConfigError("Invalid port number.") from e
|
|
160
162
|
if cp.has_option(self._CONNECT_SECTION, "database"):
|
|
161
163
|
self.db = cp.get(self._CONNECT_SECTION, "database")
|
|
162
164
|
if self.db is None:
|
|
@@ -174,13 +176,18 @@ class ConfigData:
|
|
|
174
176
|
if cp.has_option(self._CONNECT_SECTION, "password_prompt"):
|
|
175
177
|
try:
|
|
176
178
|
self.passwd_prompt = cp.getboolean(self._CONNECT_SECTION, "password_prompt")
|
|
177
|
-
except Exception:
|
|
178
|
-
raise ConfigError("Invalid argument for password_prompt.")
|
|
179
|
+
except Exception as e:
|
|
180
|
+
raise ConfigError("Invalid argument for password_prompt.") from e
|
|
181
|
+
if cp.has_option(self._CONNECT_SECTION, "use_keyring"):
|
|
182
|
+
try:
|
|
183
|
+
self.use_keyring = cp.getboolean(self._CONNECT_SECTION, "use_keyring")
|
|
184
|
+
except Exception as e:
|
|
185
|
+
raise ConfigError("Invalid argument for use_keyring.") from e
|
|
179
186
|
if cp.has_option(self._CONNECT_SECTION, "new_db"):
|
|
180
187
|
try:
|
|
181
188
|
self.new_db = cp.getboolean(self._CONNECT_SECTION, "new_db")
|
|
182
|
-
except Exception:
|
|
183
|
-
raise ConfigError("Invalid argument for new_db.")
|
|
189
|
+
except Exception as e:
|
|
190
|
+
raise ConfigError("Invalid argument for new_db.") from e
|
|
184
191
|
if cp.has_option(self._ENCODING_SECTION, "database"):
|
|
185
192
|
self.db_encoding = cp.get(self._ENCODING_SECTION, "database")
|
|
186
193
|
if cp.has_option(self._ENCODING_SECTION, "script"):
|
|
@@ -203,178 +210,183 @@ class ConfigData:
|
|
|
203
210
|
if cp.has_option(self._INPUT_SECTION, "max_int"):
|
|
204
211
|
try:
|
|
205
212
|
maxint = cp.getint(self._INPUT_SECTION, "max_int")
|
|
206
|
-
except Exception:
|
|
207
|
-
raise ConfigError("Invalid argument to max_int.")
|
|
213
|
+
except Exception as e:
|
|
214
|
+
raise ConfigError("Invalid argument to max_int.") from e
|
|
208
215
|
else:
|
|
209
216
|
self.max_int = maxint
|
|
210
217
|
if cp.has_option(self._INPUT_SECTION, "boolean_int"):
|
|
211
218
|
try:
|
|
212
219
|
self.boolean_int = cp.getboolean(self._INPUT_SECTION, "boolean_int")
|
|
213
|
-
except Exception:
|
|
214
|
-
raise ConfigError("Invalid argument to boolean_int.")
|
|
220
|
+
except Exception as e:
|
|
221
|
+
raise ConfigError("Invalid argument to boolean_int.") from e
|
|
215
222
|
if cp.has_option(self._INPUT_SECTION, "boolean_words"):
|
|
216
223
|
try:
|
|
217
224
|
self.boolean_words = cp.getboolean(self._INPUT_SECTION, "boolean_words")
|
|
218
|
-
except Exception:
|
|
219
|
-
raise ConfigError("Invalid argument to boolean_words.")
|
|
225
|
+
except Exception as e:
|
|
226
|
+
raise ConfigError("Invalid argument to boolean_words.") from e
|
|
220
227
|
if cp.has_option(self._INPUT_SECTION, "empty_strings"):
|
|
221
228
|
try:
|
|
222
229
|
self.empty_strings = cp.getboolean(self._INPUT_SECTION, "empty_strings")
|
|
223
|
-
except Exception:
|
|
224
|
-
raise ConfigError("Invalid argument to empty_strings.")
|
|
230
|
+
except Exception as e:
|
|
231
|
+
raise ConfigError("Invalid argument to empty_strings.") from e
|
|
225
232
|
if cp.has_option(self._INPUT_SECTION, "only_strings"):
|
|
226
233
|
try:
|
|
227
|
-
self.
|
|
228
|
-
except Exception:
|
|
229
|
-
raise ConfigError("Invalid argument to only_strings.")
|
|
234
|
+
self.only_strings = cp.getboolean(self._INPUT_SECTION, "only_strings")
|
|
235
|
+
except Exception as e:
|
|
236
|
+
raise ConfigError("Invalid argument to only_strings.") from e
|
|
230
237
|
if cp.has_option(self._INPUT_SECTION, "empty_rows"):
|
|
231
238
|
try:
|
|
232
239
|
self.empty_rows = cp.getboolean(self._INPUT_SECTION, "empty_rows")
|
|
233
|
-
except Exception:
|
|
234
|
-
raise ConfigError("Invalid argument to empty_rows.")
|
|
240
|
+
except Exception as e:
|
|
241
|
+
raise ConfigError("Invalid argument to empty_rows.") from e
|
|
235
242
|
if cp.has_option(self._INPUT_SECTION, "delete_empty_columns"):
|
|
236
243
|
try:
|
|
237
244
|
self.del_empty_cols = cp.getboolean(self._INPUT_SECTION, "delete_empty_columns")
|
|
238
|
-
except Exception:
|
|
239
|
-
raise ConfigError("Invalid argument to delete_empty_columns.")
|
|
245
|
+
except Exception as e:
|
|
246
|
+
raise ConfigError("Invalid argument to delete_empty_columns.") from e
|
|
240
247
|
if cp.has_option(self._INPUT_SECTION, "create_column_headers"):
|
|
241
248
|
try:
|
|
242
249
|
self.create_col_hdrs = cp.getboolean(self._INPUT_SECTION, "create_column_headers")
|
|
243
|
-
except Exception:
|
|
244
|
-
raise ConfigError("Invalid argument to create_column_headers.")
|
|
250
|
+
except Exception as e:
|
|
251
|
+
raise ConfigError("Invalid argument to create_column_headers.") from e
|
|
245
252
|
if cp.has_option(self._INPUT_SECTION, "trim_column_headers"):
|
|
246
253
|
try:
|
|
247
254
|
self.trim_col_hdrs = cp.get(self._INPUT_SECTION, "trim_column_headers").lower()
|
|
248
|
-
except Exception:
|
|
249
|
-
raise ConfigError("Invalid argument to trim_column_headers.")
|
|
255
|
+
except Exception as e:
|
|
256
|
+
raise ConfigError("Invalid argument to trim_column_headers.") from e
|
|
250
257
|
if self.trim_col_hdrs not in ("none", "both", "left", "right"):
|
|
251
258
|
raise ConfigError(f"Invalid argument to trim_column_headers: {self.trim_col_hdrs}.")
|
|
252
259
|
if cp.has_option(self._INPUT_SECTION, "clean_column_headers"):
|
|
253
260
|
try:
|
|
254
261
|
self.clean_col_hdrs = cp.getboolean(self._INPUT_SECTION, "clean_column_headers")
|
|
255
|
-
except Exception:
|
|
256
|
-
raise ConfigError("Invalid argument to clean_column_headers.")
|
|
262
|
+
except Exception as e:
|
|
263
|
+
raise ConfigError("Invalid argument to clean_column_headers.") from e
|
|
257
264
|
if cp.has_option(self._INPUT_SECTION, "fold_column_headers"):
|
|
258
265
|
foldspec = cp.get(self._INPUT_SECTION, "fold_column_headers").lower()
|
|
259
266
|
if foldspec not in ("no", "lower", "upper"):
|
|
260
267
|
raise ConfigError(f"Invalid argument to fold_column_headers: {foldspec}.")
|
|
261
|
-
self.
|
|
268
|
+
self.fold_col_hdrs = foldspec
|
|
262
269
|
if cp.has_option(self._INPUT_SECTION, "dedup_column_headers"):
|
|
263
270
|
try:
|
|
264
271
|
self.dedup_col_hdrs = cp.getboolean(self._INPUT_SECTION, "dedup_column_headers")
|
|
265
|
-
except Exception:
|
|
266
|
-
raise ConfigError("Invalid argument to dedup_column_headers.")
|
|
272
|
+
except Exception as e:
|
|
273
|
+
raise ConfigError("Invalid argument to dedup_column_headers.") from e
|
|
267
274
|
if cp.has_option(self._INPUT_SECTION, "trim_strings"):
|
|
268
275
|
try:
|
|
269
276
|
self.trim_strings = cp.getboolean(self._INPUT_SECTION, "trim_strings")
|
|
270
|
-
except Exception:
|
|
271
|
-
raise ConfigError("Invalid argument to trim_strings.")
|
|
277
|
+
except Exception as e:
|
|
278
|
+
raise ConfigError("Invalid argument to trim_strings.") from e
|
|
272
279
|
if cp.has_option(self._INPUT_SECTION, "replace_newlines"):
|
|
273
280
|
try:
|
|
274
|
-
self.
|
|
275
|
-
except Exception:
|
|
276
|
-
raise ConfigError("Invalid argument to replace_newlines.")
|
|
281
|
+
self.replace_newlines = cp.getboolean(self._INPUT_SECTION, "replace_newlines")
|
|
282
|
+
except Exception as e:
|
|
283
|
+
raise ConfigError("Invalid argument to replace_newlines.") from e
|
|
277
284
|
if cp.has_option(self._INPUT_SECTION, "import_row_buffer"):
|
|
278
285
|
try:
|
|
279
|
-
self.
|
|
280
|
-
except Exception:
|
|
281
|
-
raise ConfigError("Invalid argument for import_row_buffer.")
|
|
286
|
+
self.import_row_buffer = cp.getint(self._INPUT_SECTION, "import_row_buffer")
|
|
287
|
+
except Exception as e:
|
|
288
|
+
raise ConfigError("Invalid argument for import_row_buffer.") from e
|
|
289
|
+
if cp.has_option(self._INPUT_SECTION, "import_progress_interval"):
|
|
290
|
+
try:
|
|
291
|
+
self.import_progress_interval = cp.getint(self._INPUT_SECTION, "import_progress_interval")
|
|
292
|
+
except Exception as e:
|
|
293
|
+
raise ConfigError("Invalid argument for import_progress_interval.") from e
|
|
282
294
|
if cp.has_option(self._INPUT_SECTION, "access_use_numeric"):
|
|
283
295
|
try:
|
|
284
296
|
self.access_use_numeric = cp.getboolean(self._INPUT_SECTION, "access_use_numeric")
|
|
285
|
-
except Exception:
|
|
286
|
-
raise ConfigError("Invalid argument to access_use_numeric.")
|
|
297
|
+
except Exception as e:
|
|
298
|
+
raise ConfigError("Invalid argument to access_use_numeric.") from e
|
|
287
299
|
if cp.has_option(self._INPUT_SECTION, "import_only_common_columns"):
|
|
288
300
|
try:
|
|
289
301
|
self.import_common_cols_only = cp.getboolean(
|
|
290
302
|
self._INPUT_SECTION,
|
|
291
303
|
"import_only_common_columns",
|
|
292
304
|
)
|
|
293
|
-
except Exception:
|
|
294
|
-
raise ConfigError("Invalid argument to import_only_common_columns.")
|
|
305
|
+
except Exception as e:
|
|
306
|
+
raise ConfigError("Invalid argument to import_only_common_columns.") from e
|
|
295
307
|
if cp.has_option(self._INPUT_SECTION, "import_common_columns_only"):
|
|
296
308
|
try:
|
|
297
309
|
self.import_common_cols_only = cp.getboolean(
|
|
298
310
|
self._INPUT_SECTION,
|
|
299
311
|
"import_common_columns_only",
|
|
300
312
|
)
|
|
301
|
-
except Exception:
|
|
302
|
-
raise ConfigError("Invalid argument to import_common_columns_only.")
|
|
313
|
+
except Exception as e:
|
|
314
|
+
raise ConfigError("Invalid argument to import_common_columns_only.") from e
|
|
303
315
|
if cp.has_option(self._INPUT_SECTION, "scan_lines"):
|
|
304
316
|
try:
|
|
305
317
|
self.scan_lines = cp.getint(self._INPUT_SECTION, "scan_lines")
|
|
306
|
-
except Exception:
|
|
307
|
-
raise ConfigError("Invalid argument to scan_lines.")
|
|
318
|
+
except Exception as e:
|
|
319
|
+
raise ConfigError("Invalid argument to scan_lines.") from e
|
|
308
320
|
if cp.has_option(self._INPUT_SECTION, "import_buffer"):
|
|
309
321
|
try:
|
|
310
322
|
self.import_buffer = cp.getint(self._INPUT_SECTION, "import_buffer") * 1024
|
|
311
|
-
except Exception:
|
|
312
|
-
raise ConfigError("Invalid argument for import_buffer.")
|
|
323
|
+
except Exception as e:
|
|
324
|
+
raise ConfigError("Invalid argument for import_buffer.") from e
|
|
313
325
|
if cp.has_option(self._OUTPUT_SECTION, "log_write_messages"):
|
|
314
326
|
try:
|
|
315
327
|
self.tee_write_log = cp.getboolean(self._OUTPUT_SECTION, "log_write_messages")
|
|
316
|
-
except Exception:
|
|
317
|
-
raise ConfigError("Invalid argument to log_write_messages")
|
|
328
|
+
except Exception as e:
|
|
329
|
+
raise ConfigError("Invalid argument to log_write_messages") from e
|
|
318
330
|
if cp.has_option(self._OUTPUT_SECTION, "hdf5_text_len"):
|
|
319
331
|
try:
|
|
320
332
|
self.hdf5_text_len = cp.getint(self._OUTPUT_SECTION, "hdf5_text_len")
|
|
321
|
-
except Exception:
|
|
322
|
-
raise ConfigError("Invalid argument to log_write_messages")
|
|
333
|
+
except Exception as e:
|
|
334
|
+
raise ConfigError("Invalid argument to log_write_messages") from e
|
|
323
335
|
if cp.has_option(self._OUTPUT_SECTION, "css_file"):
|
|
324
336
|
self.css_file = cp.get(self._OUTPUT_SECTION, "css_file")
|
|
325
337
|
if self.css_file is None:
|
|
326
338
|
raise ConfigError("The css_file name is missing.")
|
|
327
339
|
if cp.has_option(self._OUTPUT_SECTION, "css_styles"):
|
|
328
340
|
self.css_styles = cp.get(self._OUTPUT_SECTION, "css_styles")
|
|
329
|
-
if self.
|
|
341
|
+
if self.css_styles is None:
|
|
330
342
|
raise ConfigError("The css_styles are missing.")
|
|
331
343
|
if cp.has_option(self._OUTPUT_SECTION, "make_export_dirs"):
|
|
332
344
|
try:
|
|
333
345
|
self.make_export_dirs = cp.getboolean(self._OUTPUT_SECTION, "make_export_dirs")
|
|
334
|
-
except Exception:
|
|
335
|
-
raise ConfigError("Invalid argument for make_export_dirs.")
|
|
346
|
+
except Exception as e:
|
|
347
|
+
raise ConfigError("Invalid argument for make_export_dirs.") from e
|
|
336
348
|
if cp.has_option(self._OUTPUT_SECTION, "quote_all_text"):
|
|
337
349
|
try:
|
|
338
350
|
self.quote_all_text = cp.getboolean(self._OUTPUT_SECTION, "quote_all_text")
|
|
339
|
-
except Exception:
|
|
340
|
-
raise ConfigError("Invalid argument for make_export_dirs.")
|
|
351
|
+
except Exception as e:
|
|
352
|
+
raise ConfigError("Invalid argument for make_export_dirs.") from e
|
|
341
353
|
if cp.has_option(self._OUTPUT_SECTION, "outfile_open_timeout"):
|
|
342
354
|
try:
|
|
343
355
|
self.outfile_open_timeout = cp.getint(self._OUTPUT_SECTION, "outfile_open_timeout")
|
|
344
|
-
except Exception:
|
|
345
|
-
raise ConfigError("Invalid argument for outfile_open_timeout.")
|
|
356
|
+
except Exception as e:
|
|
357
|
+
raise ConfigError("Invalid argument for outfile_open_timeout.") from e
|
|
346
358
|
if cp.has_option(self._OUTPUT_SECTION, "export_row_buffer"):
|
|
347
359
|
try:
|
|
348
360
|
self.export_row_buffer = cp.getint(self._OUTPUT_SECTION, "export_row_buffer")
|
|
349
|
-
except Exception:
|
|
350
|
-
raise ConfigError("Invalid argument for export_row_buffer.")
|
|
361
|
+
except Exception as e:
|
|
362
|
+
raise ConfigError("Invalid argument for export_row_buffer.") from e
|
|
351
363
|
if cp.has_option(self._OUTPUT_SECTION, "template_processor"):
|
|
352
364
|
tp = cp.get(self._OUTPUT_SECTION, "template_processor").lower()
|
|
353
|
-
if tp not in ("jinja",
|
|
365
|
+
if tp not in ("jinja",):
|
|
354
366
|
raise ConfigError(f"Invalid template processor name: {tp}")
|
|
355
367
|
self.template_processor = tp
|
|
356
368
|
if cp.has_option(self._OUTPUT_SECTION, "zip_buffer_mb"):
|
|
357
369
|
try:
|
|
358
370
|
self.zip_buffer_mb = cp.getint(self._OUTPUT_SECTION, "zip_buffer_mb")
|
|
359
|
-
except Exception:
|
|
360
|
-
raise ConfigError("Invalid argument for zip_buffer_mb.")
|
|
371
|
+
except Exception as e:
|
|
372
|
+
raise ConfigError("Invalid argument for zip_buffer_mb.") from e
|
|
361
373
|
if cp.has_option(self._INTERFACE_SECTION, "write_warnings"):
|
|
362
374
|
try:
|
|
363
375
|
self.write_warnings = cp.getboolean(self._INTERFACE_SECTION, "write_warnings")
|
|
364
|
-
except Exception:
|
|
365
|
-
raise ConfigError("Invalid argument to write_warnings.")
|
|
376
|
+
except Exception as e:
|
|
377
|
+
raise ConfigError("Invalid argument to write_warnings.") from e
|
|
366
378
|
if cp.has_option(self._INTERFACE_SECTION, "write_prefix"):
|
|
367
379
|
try:
|
|
368
380
|
self.write_prefix = cp.get(self._INTERFACE_SECTION, "write_prefix")
|
|
369
|
-
except Exception:
|
|
370
|
-
raise ConfigError("Invalid or missing argument to write_prefix.")
|
|
381
|
+
except Exception as e:
|
|
382
|
+
raise ConfigError("Invalid or missing argument to write_prefix.") from e
|
|
371
383
|
if self.write_prefix.lower() == "clear":
|
|
372
384
|
self.write_prefix = None
|
|
373
385
|
if cp.has_option(self._INTERFACE_SECTION, "write_suffix"):
|
|
374
386
|
try:
|
|
375
387
|
self.write_suffix = cp.get(self._INTERFACE_SECTION, "write_suffix")
|
|
376
|
-
except Exception:
|
|
377
|
-
raise ConfigError("Invalid or missing argument to write_suffix.")
|
|
388
|
+
except Exception as e:
|
|
389
|
+
raise ConfigError("Invalid or missing argument to write_suffix.") from e
|
|
378
390
|
if self.write_suffix.lower() == "clear":
|
|
379
391
|
self.write_suffix = None
|
|
380
392
|
if cp.has_option(self._INTERFACE_SECTION, "gui_level"):
|
|
@@ -389,57 +401,57 @@ class ConfigData:
|
|
|
389
401
|
if cp.has_option(self._INTERFACE_SECTION, "console_height"):
|
|
390
402
|
try:
|
|
391
403
|
self.gui_console_height = max(5, cp.getint(self._INTERFACE_SECTION, "console_height"))
|
|
392
|
-
except Exception:
|
|
393
|
-
raise ConfigError("Invalid argument for console_height.")
|
|
404
|
+
except Exception as e:
|
|
405
|
+
raise ConfigError("Invalid argument for console_height.") from e
|
|
394
406
|
if cp.has_option(self._INTERFACE_SECTION, "console_width"):
|
|
395
407
|
try:
|
|
396
408
|
self.gui_console_width = max(20, cp.getint(self._INTERFACE_SECTION, "console_width"))
|
|
397
|
-
except Exception:
|
|
398
|
-
raise ConfigError("Invalid argument for console_width.")
|
|
409
|
+
except Exception as e:
|
|
410
|
+
raise ConfigError("Invalid argument for console_width.") from e
|
|
399
411
|
if cp.has_option(self._INTERFACE_SECTION, "console_wait_when_done"):
|
|
400
412
|
try:
|
|
401
413
|
self.gui_wait_on_exit = cp.getboolean(self._INTERFACE_SECTION, "console_wait_when_done")
|
|
402
|
-
except Exception:
|
|
403
|
-
raise ConfigError("Invalid argument for console_wait_when_done.")
|
|
414
|
+
except Exception as e:
|
|
415
|
+
raise ConfigError("Invalid argument for console_wait_when_done.") from e
|
|
404
416
|
if cp.has_option(self._INTERFACE_SECTION, "console_wait_when_error_halt"):
|
|
405
417
|
try:
|
|
406
418
|
self.gui_wait_on_error_halt = cp.getboolean(
|
|
407
419
|
self._INTERFACE_SECTION,
|
|
408
420
|
"console_wait_when_error_halt",
|
|
409
421
|
)
|
|
410
|
-
except Exception:
|
|
411
|
-
raise ConfigError("Invalid argument for console_wait_when_error_halt.")
|
|
422
|
+
except Exception as e:
|
|
423
|
+
raise ConfigError("Invalid argument for console_wait_when_error_halt.") from e
|
|
412
424
|
if cp.has_option(self._CONFIG_SECTION, "config_file"):
|
|
413
425
|
conffile = cp.get(self._CONFIG_SECTION, "config_file")
|
|
414
426
|
if os.name == "posix" and conffile[0] == "~":
|
|
415
427
|
if len(conffile) == 1:
|
|
416
|
-
conffile =
|
|
428
|
+
conffile = str(Path("~").expanduser())
|
|
417
429
|
elif len(conffile) > 1 and conffile[1] == os.sep:
|
|
418
|
-
conffile =
|
|
430
|
+
conffile = str(Path("~").expanduser() / conffile[2:])
|
|
419
431
|
conffile = variable_pool.substitute(conffile)[0]
|
|
420
|
-
if not
|
|
421
|
-
conffile =
|
|
422
|
-
if
|
|
432
|
+
if not Path(conffile).is_file():
|
|
433
|
+
conffile = str(Path(conffile) / self.config_file_name)
|
|
434
|
+
if Path(conffile).is_file():
|
|
423
435
|
# Silently ignore a non-existent file, for cross-OS compatibility.
|
|
424
436
|
config_files.insert(ix + 1, conffile)
|
|
425
437
|
if os.name == "posix" and cp.has_option(self._CONFIG_SECTION, "linux_config_file"):
|
|
426
438
|
conffile = cp.get(self._CONFIG_SECTION, "linux_config_file")
|
|
427
439
|
if conffile[0] == "~":
|
|
428
440
|
if len(conffile) == 1:
|
|
429
|
-
conffile =
|
|
441
|
+
conffile = str(Path("~").expanduser())
|
|
430
442
|
elif len(conffile) > 1 and conffile[1] == os.sep:
|
|
431
|
-
conffile =
|
|
443
|
+
conffile = str(Path("~").expanduser() / conffile[2:])
|
|
432
444
|
conffile = variable_pool.substitute(conffile)[0]
|
|
433
|
-
if not
|
|
434
|
-
conffile =
|
|
435
|
-
if
|
|
445
|
+
if not Path(conffile).is_file():
|
|
446
|
+
conffile = str(Path(conffile) / self.config_file_name)
|
|
447
|
+
if Path(conffile).is_file():
|
|
436
448
|
config_files.insert(ix + 1, conffile)
|
|
437
449
|
if os.name == "windows" and cp.has_option(self._CONFIG_SECTION, "win_config_file"):
|
|
438
450
|
conffile = cp.get(self._CONFIG_SECTION, "win_config_file")
|
|
439
451
|
conffile = variable_pool.substitute(conffile)[0]
|
|
440
|
-
if not
|
|
441
|
-
conffile =
|
|
442
|
-
if
|
|
452
|
+
if not Path(conffile).is_file():
|
|
453
|
+
conffile = str(Path(conffile) / self.config_file_name)
|
|
454
|
+
if Path(conffile).is_file():
|
|
443
455
|
config_files.insert(ix + 1, conffile)
|
|
444
456
|
if cp.has_option(self._CONFIG_SECTION, "user_logfile"):
|
|
445
457
|
self.user_logfile = cp.getboolean(self._CONFIG_SECTION, "user_logfile")
|
|
@@ -452,16 +464,21 @@ class ConfigData:
|
|
|
452
464
|
if cp.has_option(self._CONFIG_SECTION, "log_datavars"):
|
|
453
465
|
try:
|
|
454
466
|
self.log_datavars = cp.getboolean(self._CONFIG_SECTION, "log_datavars")
|
|
455
|
-
except Exception:
|
|
456
|
-
raise ConfigError("Invalid argument to log_datavars setting.")
|
|
467
|
+
except Exception as e:
|
|
468
|
+
raise ConfigError("Invalid argument to log_datavars setting.") from e
|
|
469
|
+
if cp.has_option(self._CONFIG_SECTION, "max_log_size_mb"):
|
|
470
|
+
try:
|
|
471
|
+
self.max_log_size_mb = cp.getint(self._CONFIG_SECTION, "max_log_size_mb")
|
|
472
|
+
except Exception as e:
|
|
473
|
+
raise ConfigError("Invalid argument to max_log_size_mb setting.") from e
|
|
457
474
|
if cp.has_option(self._EMAIL_SECTION, "host"):
|
|
458
475
|
self.smtp_host = cp.get(self._EMAIL_SECTION, "host")
|
|
459
476
|
if cp.has_option(self._EMAIL_SECTION, "port"):
|
|
460
477
|
self.smtp_port = cp.get(self._EMAIL_SECTION, "port")
|
|
461
478
|
try:
|
|
462
479
|
self.smtp_port = cp.getint(self._EMAIL_SECTION, "port")
|
|
463
|
-
except Exception:
|
|
464
|
-
raise ConfigError("Invalid argument for email port.")
|
|
480
|
+
except Exception as e:
|
|
481
|
+
raise ConfigError("Invalid argument for email port.") from e
|
|
465
482
|
if cp.has_option(self._EMAIL_SECTION, "username"):
|
|
466
483
|
self.smtp_username = cp.get(self._EMAIL_SECTION, "username")
|
|
467
484
|
if cp.has_option(self._EMAIL_SECTION, "password"):
|
|
@@ -471,13 +488,13 @@ class ConfigData:
|
|
|
471
488
|
if cp.has_option(self._EMAIL_SECTION, "use_ssl"):
|
|
472
489
|
try:
|
|
473
490
|
self.smtp_ssl = cp.getboolean(self._EMAIL_SECTION, "use_ssl")
|
|
474
|
-
except Exception:
|
|
475
|
-
raise ConfigError("Invalid argument for email use_ssl.")
|
|
491
|
+
except Exception as e:
|
|
492
|
+
raise ConfigError("Invalid argument for email use_ssl.") from e
|
|
476
493
|
if cp.has_option(self._EMAIL_SECTION, "use_tls"):
|
|
477
494
|
try:
|
|
478
495
|
self.smtp_tls = cp.getboolean(self._EMAIL_SECTION, "use_tls")
|
|
479
|
-
except Exception:
|
|
480
|
-
raise ConfigError("Invalid argument for email use_tls.")
|
|
496
|
+
except Exception as e:
|
|
497
|
+
raise ConfigError("Invalid argument for email use_tls.") from e
|
|
481
498
|
if cp.has_option(self._EMAIL_SECTION, "email_format"):
|
|
482
499
|
fmt = cp.get(self._EMAIL_SECTION, "email_format").lower()
|
|
483
500
|
if fmt not in ("plain", "html"):
|
|
@@ -494,23 +511,26 @@ class ConfigData:
|
|
|
494
511
|
if cp.has_section(self._INCLUDE_REQ_SECTION):
|
|
495
512
|
imp_items = cp.items(self._INCLUDE_REQ_SECTION)
|
|
496
513
|
ord_items = sorted([(int(i[0]), i[1]) for i in imp_items], key=lambda x: x[0])
|
|
497
|
-
newfiles = [
|
|
514
|
+
newfiles = [str(Path(f[1]).resolve()) for f in ord_items]
|
|
498
515
|
u_files = []
|
|
499
516
|
for f in newfiles:
|
|
500
517
|
if not (f in u_files or f in self.include_req or f in self.include_opt) and f != current_script:
|
|
501
|
-
if not
|
|
518
|
+
if not Path(f).exists():
|
|
502
519
|
raise ConfigError(f"Required include file {f} does not exist.")
|
|
503
520
|
u_files.append(f)
|
|
504
521
|
self.include_req.extend(u_files)
|
|
505
522
|
if cp.has_section(self._INCLUDE_OPT_SECTION):
|
|
506
523
|
imp_items = cp.items(self._INCLUDE_OPT_SECTION)
|
|
507
524
|
ord_items = sorted([(int(i[0]), i[1]) for i in imp_items], key=lambda x: x[0])
|
|
508
|
-
newfiles = [
|
|
525
|
+
newfiles = [str(Path(f[1]).resolve()) for f in ord_items]
|
|
509
526
|
u_files = []
|
|
510
527
|
for f in newfiles:
|
|
511
|
-
if
|
|
512
|
-
|
|
513
|
-
|
|
528
|
+
if (
|
|
529
|
+
not (f in u_files or f in self.include_req or f in self.include_opt)
|
|
530
|
+
and f != current_script
|
|
531
|
+
and Path(f).exists()
|
|
532
|
+
):
|
|
533
|
+
u_files.append(f)
|
|
514
534
|
self.include_opt.extend(u_files)
|
|
515
535
|
|
|
516
536
|
|