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/utils/mail.py
CHANGED
|
@@ -10,10 +10,8 @@ which compose and send email via SMTP using settings from
|
|
|
10
10
|
metacommand and the halt/cancel email-notification hooks.
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
-
import io
|
|
14
|
-
import os
|
|
15
13
|
import re
|
|
16
|
-
from
|
|
14
|
+
from pathlib import Path
|
|
17
15
|
|
|
18
16
|
import execsql.state as _state
|
|
19
17
|
from execsql.exceptions import ErrInfo
|
|
@@ -67,9 +65,9 @@ class Mailer:
|
|
|
67
65
|
send_from: str,
|
|
68
66
|
send_to: str,
|
|
69
67
|
subject: str,
|
|
70
|
-
msg_content:
|
|
71
|
-
content_filename:
|
|
72
|
-
attach_filename:
|
|
68
|
+
msg_content: str | None,
|
|
69
|
+
content_filename: str | None = None,
|
|
70
|
+
attach_filename: str | None = None,
|
|
73
71
|
) -> None:
|
|
74
72
|
global smtplib
|
|
75
73
|
global MIMEMultipart
|
|
@@ -89,24 +87,24 @@ class Mailer:
|
|
|
89
87
|
if conf.email_format == "html":
|
|
90
88
|
msg_body = "<html><head>"
|
|
91
89
|
if conf.email_css is not None:
|
|
92
|
-
msg_body += "<style
|
|
93
|
-
msg_body += "</head><body
|
|
90
|
+
msg_body += f"<style>{conf.email_css}</style>"
|
|
91
|
+
msg_body += f"</head><body>{msg_content}" if msg_content else ""
|
|
94
92
|
else:
|
|
95
93
|
msg_body = msg_content if msg_content else ""
|
|
96
94
|
if content_filename is not None:
|
|
97
|
-
|
|
95
|
+
with open(content_filename) as content_file:
|
|
96
|
+
msg_body += "\n" + content_file.read()
|
|
98
97
|
if conf.email_format == "html":
|
|
99
98
|
msg_body += "</body></html>"
|
|
100
99
|
msg.attach(MIMEText(msg_body, "html"))
|
|
101
100
|
else:
|
|
102
101
|
msg.attach(MIMEText(msg_body, "plain"))
|
|
103
102
|
if attach_filename is not None:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
f.close()
|
|
103
|
+
with open(attach_filename, "rb") as f:
|
|
104
|
+
fdata = MIMEBase("application", "octet-stream")
|
|
105
|
+
fdata.set_payload(f.read())
|
|
108
106
|
encoders.encode_base64(fdata)
|
|
109
|
-
fdata.add_header("Content-Disposition", "attachment", filename=
|
|
107
|
+
fdata.add_header("Content-Disposition", "attachment", filename=Path(attach_filename).name)
|
|
110
108
|
msg.attach(fdata)
|
|
111
109
|
self.smtpconn.sendmail(send_from, recipients, msg.as_string())
|
|
112
110
|
|
|
@@ -117,9 +115,9 @@ class MailSpec:
|
|
|
117
115
|
send_from: str,
|
|
118
116
|
send_to: str,
|
|
119
117
|
subject: str,
|
|
120
|
-
msg_content:
|
|
121
|
-
content_filename:
|
|
122
|
-
attach_filename:
|
|
118
|
+
msg_content: str | None,
|
|
119
|
+
content_filename: str | None = None,
|
|
120
|
+
attach_filename: str | None = None,
|
|
123
121
|
repeatable: bool = False,
|
|
124
122
|
) -> None:
|
|
125
123
|
self.send_from = send_from
|
execsql/utils/numeric.py
CHANGED
|
@@ -12,9 +12,8 @@ Provides:
|
|
|
12
12
|
string, used by the ``FORMAT NUMBER`` substitution variant.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
-
import math
|
|
16
15
|
import re
|
|
17
|
-
from typing import Any
|
|
16
|
+
from typing import Any
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
def leading_zero_num(dataval: Any) -> bool:
|
|
@@ -42,7 +41,7 @@ def leading_zero_num(dataval: Any) -> bool:
|
|
|
42
41
|
return False
|
|
43
42
|
|
|
44
43
|
|
|
45
|
-
def as_numeric(strval: Any) ->
|
|
44
|
+
def as_numeric(strval: Any) -> int | float | None:
|
|
46
45
|
# Converts the given value to an int, a float, or None.
|
|
47
46
|
if type(strval) in (int, float):
|
|
48
47
|
return strval
|
execsql/utils/regex.py
CHANGED
|
@@ -13,19 +13,17 @@ dispatch regexes at module load time:
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
import os
|
|
16
|
-
import re
|
|
17
|
-
from typing import List, Optional, Tuple
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
def ins_rxs(rx_list: tuple, fragment1: object, fragment2: object) -> tuple:
|
|
21
19
|
# Returns a tuple of all strings consisting of elements of the 'rx_list' tuple
|
|
22
20
|
# inserted between 'fragment1' and 'fragment2'. The fragments may themselves
|
|
23
21
|
# be tuples.
|
|
24
|
-
if
|
|
22
|
+
if not isinstance(fragment1, tuple):
|
|
25
23
|
fragment1 = (fragment1,)
|
|
26
24
|
if fragment2 is None:
|
|
27
25
|
fragment2 = ("",)
|
|
28
|
-
if
|
|
26
|
+
if not isinstance(fragment2, tuple):
|
|
29
27
|
fragment2 = (fragment2,)
|
|
30
28
|
rv = []
|
|
31
29
|
for te in rx_list:
|
|
@@ -36,10 +34,10 @@ def ins_rxs(rx_list: tuple, fragment1: object, fragment2: object) -> tuple:
|
|
|
36
34
|
|
|
37
35
|
|
|
38
36
|
def ins_quoted_rx(fragment1: object, fragment2: object, rx: str) -> tuple:
|
|
39
|
-
return ins_rxs((rx,
|
|
37
|
+
return ins_rxs((rx, rf'"{rx}"'), fragment1, fragment2)
|
|
40
38
|
|
|
41
39
|
|
|
42
|
-
def ins_schema_rxs(fragment1: object, fragment2: object, suffix:
|
|
40
|
+
def ins_schema_rxs(fragment1: object, fragment2: object, suffix: str | None = None) -> tuple:
|
|
43
41
|
schema_exprs = (
|
|
44
42
|
r'"(?P<schema>[A-Za-z0-9_\- ]+)"',
|
|
45
43
|
r"(?P<schema>[A-Za-z0-9_\-]+)",
|
|
@@ -50,7 +48,7 @@ def ins_schema_rxs(fragment1: object, fragment2: object, suffix: Optional[str] =
|
|
|
50
48
|
return ins_rxs(schema_exprs, fragment1, fragment2)
|
|
51
49
|
|
|
52
50
|
|
|
53
|
-
def ins_table_rxs(fragment1: object, fragment2: object, suffix:
|
|
51
|
+
def ins_table_rxs(fragment1: object, fragment2: object, suffix: str | None = None) -> tuple:
|
|
54
52
|
tbl_exprs = (
|
|
55
53
|
r'(?:"(?P<schema>[A-Za-z0-9_\- ]+)"\.)?"(?P<table>[A-Za-z0-9_\-\# ]+)"',
|
|
56
54
|
r"(?:(?P<schema>[A-Za-z0-9_\-]+)\.)?(?P<table>[A-Za-z0-9_\-\#]+)",
|
|
@@ -79,13 +77,12 @@ def ins_table_list_rxs(fragment1: object, fragment2: object) -> tuple:
|
|
|
79
77
|
def ins_fn_rxs(fragment1: object, fragment2: object, symbolicname: str = "filename") -> tuple:
|
|
80
78
|
if os.name == "posix":
|
|
81
79
|
fns = (
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
rf"(?P<{symbolicname}>[\w\.\-\\\/\'~`!@#$^&()+={{}}\[\]:;,]*[\w\.\-\\\/\'~`!@#$^&(+={{}}\[\]:;,])",
|
|
81
|
+
rf'"(?P<{symbolicname}>[\w\s\.\-\\\/\'~`!@#$^&()+={{}}\[\]:;,]+)"',
|
|
84
82
|
)
|
|
85
83
|
else:
|
|
86
84
|
fns = (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
r'"(?P<%s>([A-Z]\:)?[\w+\,()!@#$^&\+=;\'{}\[\]~`\s\.\-\\\/]+)"' % symbolicname,
|
|
85
|
+
rf"(?P<{symbolicname}>([A-Z]\:)?[\w+\,()!@#$^&\+=;\'{{}}\[\]~`\.\-\\\/]*[\w+\,(!@#$^&\+=;\'{{}}\[\]~`\.\-\\\/])",
|
|
86
|
+
rf'"(?P<{symbolicname}>([A-Z]\:)?[\w+\,()!@#$^&\+=;\'{{}}\[\]~`\s\.\-\\\/]+)"',
|
|
90
87
|
)
|
|
91
88
|
return ins_rxs(fns, fragment1, fragment2)
|
execsql/utils/strings.py
CHANGED
|
@@ -22,7 +22,6 @@ identifiers:
|
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
24
|
import re
|
|
25
|
-
from typing import Any, List, Optional
|
|
26
25
|
|
|
27
26
|
|
|
28
27
|
def clean_word(word: str) -> str:
|
|
@@ -34,7 +33,7 @@ def clean_word(word: str) -> str:
|
|
|
34
33
|
return s1
|
|
35
34
|
|
|
36
35
|
|
|
37
|
-
def clean_words(wordlist:
|
|
36
|
+
def clean_words(wordlist: list[str]) -> list[str]:
|
|
38
37
|
return [clean_word(w) for w in wordlist]
|
|
39
38
|
|
|
40
39
|
|
|
@@ -50,7 +49,7 @@ def trim_word(word: str, blr: str) -> str:
|
|
|
50
49
|
return word
|
|
51
50
|
|
|
52
51
|
|
|
53
|
-
def trim_words(wordlist:
|
|
52
|
+
def trim_words(wordlist: list[str], nblr: str) -> list[str]:
|
|
54
53
|
return [trim_word(w, nblr) for w in wordlist]
|
|
55
54
|
|
|
56
55
|
|
|
@@ -63,16 +62,16 @@ def fold_word(word: str, foldspec: str) -> str:
|
|
|
63
62
|
return word
|
|
64
63
|
|
|
65
64
|
|
|
66
|
-
def fold_words(wordlist:
|
|
65
|
+
def fold_words(wordlist: list[str], foldspec: str) -> list[str]:
|
|
67
66
|
return [fold_word(w, foldspec) for w in wordlist]
|
|
68
67
|
|
|
69
68
|
|
|
70
|
-
def dedup_words(wordlist:
|
|
69
|
+
def dedup_words(wordlist: list[str]) -> list[str]:
|
|
71
70
|
# Adds an item number suffix to duplicated words.
|
|
72
71
|
w2 = wordlist
|
|
73
72
|
dup_ix = [ix for ix, w in enumerate(w2) if w.lower() in [wrd.lower() for wrd in w2[:ix]]]
|
|
74
73
|
while len(dup_ix) > 0:
|
|
75
|
-
w2 = [w + "_
|
|
74
|
+
w2 = [w + f"_{str(ix + 1)}" if ix in dup_ix else w for ix, w in enumerate(w2)]
|
|
76
75
|
dup_ix = [ix for ix, w in enumerate(w2) if w.lower() in [wrd.lower() for wrd in w2[:ix]]]
|
|
77
76
|
return w2
|
|
78
77
|
|
|
@@ -206,10 +205,7 @@ def encodings_match(enc1: str, enc2: str) -> bool:
|
|
|
206
205
|
"gb18030",
|
|
207
206
|
),
|
|
208
207
|
)
|
|
209
|
-
for eq in equivalents
|
|
210
|
-
if enc1 in eq and enc2 in eq:
|
|
211
|
-
return True
|
|
212
|
-
return False
|
|
208
|
+
return any(enc1 in eq and enc2 in eq for eq in equivalents)
|
|
213
209
|
|
|
214
210
|
|
|
215
211
|
def wo_quotes(argstr: str) -> str:
|
|
@@ -247,8 +243,10 @@ def get_subvarset(varname: str, metacommandline: str) -> tuple:
|
|
|
247
243
|
raise ErrInfo(
|
|
248
244
|
type="cmd",
|
|
249
245
|
command_text=metacommandline,
|
|
250
|
-
other_msg="Outer-scope referent variable (
|
|
251
|
-
|
|
246
|
+
other_msg="Outer-scope referent variable ({}) has no matching local variable ({}).".format(
|
|
247
|
+
re.sub("^[~]", "+", varname),
|
|
248
|
+
varname,
|
|
249
|
+
),
|
|
252
250
|
)
|
|
253
251
|
# Global or local variable
|
|
254
252
|
else:
|
execsql/utils/timer.py
CHANGED
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
#outfile_open_timeout=600
|
|
178
178
|
|
|
179
179
|
# The name of the template processor to be used when exporting data using a template.
|
|
180
|
-
#
|
|
180
|
+
# Value: jinja.
|
|
181
181
|
#template_processor=
|
|
182
182
|
|
|
183
183
|
# The size of the internal buffer used when the EXPORT metacommand exports data to
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: execsql2
|
|
3
|
+
Version: 2.1.2
|
|
4
|
+
Summary: Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables.
|
|
5
|
+
Project-URL: Repository, https://github.com/geocoug/execsql
|
|
6
|
+
Project-URL: Issues, https://github.com/geocoug/execsql/issues
|
|
7
|
+
Author-email: Dreas Nielsen <cortice@tutanota.com>
|
|
8
|
+
Maintainer-email: Caleb Grant <grantcaleb22@gmail.com>
|
|
9
|
+
License: execsql2 — a fork of execsql.py
|
|
10
|
+
Copyright (c) 2007-2025 R.Dreas Nielsen
|
|
11
|
+
Copyright (c) 2026-present Caleb Grant
|
|
12
|
+
|
|
13
|
+
This program is free software: you can redistribute it and/or modify it under
|
|
14
|
+
the terms of the GNU General Public License as published by the Free Software
|
|
15
|
+
Foundation, either version 3 of the License, or (at your option) any later
|
|
16
|
+
version. This program is distributed in the hope that it will be useful, but
|
|
17
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
19
|
+
details. The GNU General Public License is available at
|
|
20
|
+
http://www.gnu.org/licenses/.
|
|
21
|
+
License-File: LICENSE.txt
|
|
22
|
+
License-File: NOTICE
|
|
23
|
+
Keywords: Access,CSV,DBMS,DuckDB,ETL,Firebird,HTML,JSON,LaTeX,MariaDB,MySQL,ODBC,OpenDocument,Oracle,PostgreSQL,Postgres,SQL,SQL Server,SQLite,TSV,XML,database,export,import,query,script,table
|
|
24
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
25
|
+
Classifier: Environment :: Console
|
|
26
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
27
|
+
Classifier: Intended Audience :: Information Technology
|
|
28
|
+
Classifier: Intended Audience :: System Administrators
|
|
29
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
30
|
+
Classifier: Natural Language :: English
|
|
31
|
+
Classifier: Operating System :: OS Independent
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
37
|
+
Classifier: Topic :: Database
|
|
38
|
+
Classifier: Topic :: Database :: Front-Ends
|
|
39
|
+
Requires-Python: >=3.10
|
|
40
|
+
Requires-Dist: rich>=13.0
|
|
41
|
+
Requires-Dist: sqlglot>=25.0
|
|
42
|
+
Requires-Dist: textual>=0.47.0
|
|
43
|
+
Requires-Dist: typer>=0.12
|
|
44
|
+
Provides-Extra: all
|
|
45
|
+
Requires-Dist: duckdb; extra == 'all'
|
|
46
|
+
Requires-Dist: firebird-driver; extra == 'all'
|
|
47
|
+
Requires-Dist: jinja2; extra == 'all'
|
|
48
|
+
Requires-Dist: keyring; extra == 'all'
|
|
49
|
+
Requires-Dist: odfpy; extra == 'all'
|
|
50
|
+
Requires-Dist: openpyxl; extra == 'all'
|
|
51
|
+
Requires-Dist: oracledb; extra == 'all'
|
|
52
|
+
Requires-Dist: polars; extra == 'all'
|
|
53
|
+
Requires-Dist: psycopg2-binary; extra == 'all'
|
|
54
|
+
Requires-Dist: pymysql; extra == 'all'
|
|
55
|
+
Requires-Dist: pyodbc; extra == 'all'
|
|
56
|
+
Requires-Dist: tables; extra == 'all'
|
|
57
|
+
Requires-Dist: xlrd; extra == 'all'
|
|
58
|
+
Provides-Extra: all-db
|
|
59
|
+
Requires-Dist: duckdb; extra == 'all-db'
|
|
60
|
+
Requires-Dist: firebird-driver; extra == 'all-db'
|
|
61
|
+
Requires-Dist: oracledb; extra == 'all-db'
|
|
62
|
+
Requires-Dist: psycopg2-binary; extra == 'all-db'
|
|
63
|
+
Requires-Dist: pymysql; extra == 'all-db'
|
|
64
|
+
Requires-Dist: pyodbc; extra == 'all-db'
|
|
65
|
+
Provides-Extra: auth
|
|
66
|
+
Requires-Dist: keyring; extra == 'auth'
|
|
67
|
+
Provides-Extra: dev
|
|
68
|
+
Requires-Dist: build>=1.2.2.post1; extra == 'dev'
|
|
69
|
+
Requires-Dist: bump-my-version>=1.2.7; extra == 'dev'
|
|
70
|
+
Requires-Dist: markdown-include>=0.8; extra == 'dev'
|
|
71
|
+
Requires-Dist: mkdocstrings-python>=2.0.3; extra == 'dev'
|
|
72
|
+
Requires-Dist: pre-commit>=3.5.0; extra == 'dev'
|
|
73
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
74
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
75
|
+
Requires-Dist: tox-uv>=1.13.1; extra == 'dev'
|
|
76
|
+
Requires-Dist: twine>=6.1.0; extra == 'dev'
|
|
77
|
+
Requires-Dist: zensical>=0.0.28; extra == 'dev'
|
|
78
|
+
Provides-Extra: duckdb
|
|
79
|
+
Requires-Dist: duckdb; extra == 'duckdb'
|
|
80
|
+
Provides-Extra: firebird
|
|
81
|
+
Requires-Dist: firebird-driver; extra == 'firebird'
|
|
82
|
+
Provides-Extra: formats
|
|
83
|
+
Requires-Dist: jinja2; extra == 'formats'
|
|
84
|
+
Requires-Dist: odfpy; extra == 'formats'
|
|
85
|
+
Requires-Dist: openpyxl; extra == 'formats'
|
|
86
|
+
Requires-Dist: polars; extra == 'formats'
|
|
87
|
+
Requires-Dist: tables; extra == 'formats'
|
|
88
|
+
Requires-Dist: xlrd; extra == 'formats'
|
|
89
|
+
Provides-Extra: mssql
|
|
90
|
+
Requires-Dist: pyodbc; extra == 'mssql'
|
|
91
|
+
Provides-Extra: mysql
|
|
92
|
+
Requires-Dist: pymysql; extra == 'mysql'
|
|
93
|
+
Provides-Extra: odbc
|
|
94
|
+
Requires-Dist: pyodbc; extra == 'odbc'
|
|
95
|
+
Provides-Extra: oracle
|
|
96
|
+
Requires-Dist: oracledb; extra == 'oracle'
|
|
97
|
+
Provides-Extra: postgres
|
|
98
|
+
Requires-Dist: psycopg2-binary; extra == 'postgres'
|
|
99
|
+
Description-Content-Type: text/markdown
|
|
100
|
+
|
|
101
|
+
> [!WARNING]
|
|
102
|
+
> **This project is in active development and is not yet stable.**
|
|
103
|
+
> The codebase is being modernized from the upstream monolith into a modular package.
|
|
104
|
+
> APIs, CLI behavior, and configuration options may change without notice.
|
|
105
|
+
> Not recommended for production use. For the stable upstream release, see [execsql](https://execsql.readthedocs.io/).
|
|
106
|
+
|
|
107
|
+
<div align="center">
|
|
108
|
+
|
|
109
|
+
<img src="https://execsql2.readthedocs.io/en/latest/images/execsql_logo_01.png" alt="execsql logo">
|
|
110
|
+
|
|
111
|
+
*Multi-DBMS SQL script processor.*
|
|
112
|
+
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div align="center">
|
|
116
|
+
|
|
117
|
+
[](https://github.com/geocoug/execsql/actions/workflows/ci-cd.yml)
|
|
118
|
+
[](https://codecov.io/gh/geocoug/execsql)
|
|
119
|
+
[](https://execsql2.readthedocs.io/)
|
|
120
|
+
[](https://pypi.org/project/execsql2/)
|
|
121
|
+
[](https://pypi.org/project/execsql2/)
|
|
122
|
+
[](https://pypi.org/project/execsql2/)
|
|
123
|
+
[](https://pepy.tech/project/execsql2)
|
|
124
|
+
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
# Fork
|
|
128
|
+
|
|
129
|
+
*execsql2* is a maintained fork of [execsql](https://execsql.readthedocs.io/) originally authored by R.Dreas Nielsen. The upstream project is no longer actively maintained. This fork is maintained by [Caleb Grant](https://github.com/geocoug) and is distributed on PyPI as `execsql2`. Complete documentation is at [execsql2.readthedocs.io](https://execsql2.readthedocs.io/).
|
|
130
|
+
|
|
131
|
+
# Overview
|
|
132
|
+
|
|
133
|
+
*execsql* runs SQL scripts against PostgreSQL, MySQL/MariaDB, SQLite, DuckDB, MS-SQL-Server, MS-Access, Firebird, Oracle, or an ODBC DSN. In addition to standard SQL, it supports a set of metacommands (embedded in SQL comments) for importing and exporting data, copying data between databases, conditional execution, looping, substitution variables, and interactive prompts. Because metacommands live in SQL comments, scripts remain valid SQL and are ignored by other tools such as `psql` or `sqlcmd`.
|
|
134
|
+
|
|
135
|
+
# Installation
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pip install execsql2
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Optional extras install database drivers and feature bundles:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Database drivers
|
|
145
|
+
pip install execsql2[postgres] # PostgreSQL (psycopg2-binary)
|
|
146
|
+
pip install execsql2[mysql] # MySQL / MariaDB (pymysql)
|
|
147
|
+
pip install execsql2[mssql] # SQL Server (pyodbc)
|
|
148
|
+
pip install execsql2[duckdb] # DuckDB
|
|
149
|
+
pip install execsql2[firebird] # Firebird (firebird-driver)
|
|
150
|
+
pip install execsql2[oracle] # Oracle (oracledb)
|
|
151
|
+
pip install execsql2[odbc] # ODBC DSN (pyodbc)
|
|
152
|
+
|
|
153
|
+
# Feature bundles
|
|
154
|
+
pip install execsql2[formats] # ODS, Excel, Jinja2, Feather, Parquet, HDF5
|
|
155
|
+
pip install execsql2[auth] # OS keyring integration
|
|
156
|
+
|
|
157
|
+
# Convenience
|
|
158
|
+
pip install execsql2[all-db] # All database drivers
|
|
159
|
+
pip install execsql2[all] # Everything
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
SQLite connections use Python's standard library and require no additional packages.
|
|
163
|
+
|
|
164
|
+
# Usage
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
execsql [OPTIONS] SQL_SCRIPT [SERVER DATABASE | DATABASE_FILE]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Examples:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
execsql -tp script.sql myserver mydb # PostgreSQL
|
|
174
|
+
execsql -tm script.sql myserver mydb # MySQL / MariaDB
|
|
175
|
+
execsql -ts script.sql myserver mydb # SQL Server
|
|
176
|
+
execsql -tl script.sql mydb.sqlite # SQLite
|
|
177
|
+
execsql -tk script.sql mydb.duckdb # DuckDB
|
|
178
|
+
execsql -to script.sql myserver myservice # Oracle
|
|
179
|
+
execsql script.sql # read connection from config file
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Supported Databases
|
|
183
|
+
|
|
184
|
+
| Flag | Database |
|
|
185
|
+
| ---- | --------------- |
|
|
186
|
+
| `p` | PostgreSQL |
|
|
187
|
+
| `m` | MySQL / MariaDB |
|
|
188
|
+
| `s` | MS SQL Server |
|
|
189
|
+
| `l` | SQLite |
|
|
190
|
+
| `k` | DuckDB |
|
|
191
|
+
| `a` | MS Access |
|
|
192
|
+
| `f` | Firebird |
|
|
193
|
+
| `o` | Oracle |
|
|
194
|
+
| `d` | ODBC DSN |
|
|
195
|
+
|
|
196
|
+
## Options
|
|
197
|
+
|
|
198
|
+
| Flag | Description |
|
|
199
|
+
| ----------------------------------- | --------------------------------------------------------------- |
|
|
200
|
+
| `-t {p,m,s,l,k,a,f,o,d}` | Database type |
|
|
201
|
+
| `-u USER` | Database username |
|
|
202
|
+
| `-p PORT` | Server port |
|
|
203
|
+
| `-a VALUE` | Set substitution variable `$ARG_x` |
|
|
204
|
+
| `-c SCRIPT` | Execute inline SQL or metacommand string |
|
|
205
|
+
| `-d` | Auto-create export directories |
|
|
206
|
+
| `-f ENCODING` | Script file encoding (default: UTF-8) |
|
|
207
|
+
| `-l` | Write run log to `~/execsql.log` |
|
|
208
|
+
| `-m` | List metacommands and exit |
|
|
209
|
+
| `-n` | Create a new SQLite or PostgreSQL database if it does not exist |
|
|
210
|
+
| `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
|
|
211
|
+
| `--gui-framework {tkinter,textual}` | GUI framework for interactive prompts |
|
|
212
|
+
| `-w` | Skip password prompt when a username is supplied |
|
|
213
|
+
|
|
214
|
+
Run `execsql --help` for the full option list, or `execsql -m` to list all metacommands.
|
|
215
|
+
|
|
216
|
+
# Features
|
|
217
|
+
|
|
218
|
+
- Import data from CSV, TSV, Excel, OpenDocument, Feather, or Parquet files into a database table.
|
|
219
|
+
- Export query results in 15+ formats including CSV, TSV, JSON, XML, HTML, LaTeX, OpenDocument, Feather, HDF5, DuckDB, SQLite, plain text, and Jinja2 templates.
|
|
220
|
+
- Copy data between databases, including across different DBMS types.
|
|
221
|
+
- Conditionally execute SQL and metacommands using `IF`/`ELSE`/`ENDIF` based on data values, DBMS type, or user input.
|
|
222
|
+
- Loop over blocks of SQL and metacommands using `LOOP`/`ENDLOOP`.
|
|
223
|
+
- Use substitution variables (`SUB`, `$ARG_x`, built-in variables like `$date_tag`) to parameterize scripts.
|
|
224
|
+
- Include or chain scripts with `INCLUDE` and `SCRIPT`.
|
|
225
|
+
- Display query results in a GUI dialog; optionally prompt the user to select a row, enter a value, or submit a form.
|
|
226
|
+
- Write status messages or tabular output to the console or a file during execution.
|
|
227
|
+
- Automatically log each run, recording databases used, scripts executed, and user responses.
|
|
228
|
+
|
|
229
|
+
# An Illustration
|
|
230
|
+
|
|
231
|
+
The following script demonstrates metacommands and substitution variables. Lines prefixed with `-- !x!` are metacommands; identifiers wrapped in `!!` are substitution variables.
|
|
232
|
+
|
|
233
|
+
```sql
|
|
234
|
+
-- ==== Configuration ====
|
|
235
|
+
-- Put the (date-tagged) logfile name in the 'inputfile' substitution variable.
|
|
236
|
+
-- !x! SUB inputfile logs/errors_!!$date_tag!!
|
|
237
|
+
-- Ensure that the export directory will be created if necessary.
|
|
238
|
+
-- !x! CONFIG MAKE_EXPORT_DIRS Yes
|
|
239
|
+
|
|
240
|
+
-- ==== Display Fatal Errors ====
|
|
241
|
+
-- !x! IF(file_exists(!!inputfile!!))
|
|
242
|
+
-- Import the data to a staging table.
|
|
243
|
+
-- !x! IMPORT TO REPLACEMENT staging.errorlog FROM !!inputfile!!
|
|
244
|
+
-- Create a view to display only fatal errors.
|
|
245
|
+
create temporary view fatals as
|
|
246
|
+
select user, run_time, process
|
|
247
|
+
from staging.errorlog
|
|
248
|
+
where severity = 'FATAL';
|
|
249
|
+
-- !x! IF(HASROWS(fatals))
|
|
250
|
+
-- Export the fatal errors to a dated report.
|
|
251
|
+
-- !x! EXPORT fatals TO reports/error_report_!!$date_tag!! AS CSV
|
|
252
|
+
-- Also display it to the user in a GUI.
|
|
253
|
+
-- !x! PROMPT MESSAGE "Fatal errors in !!inputfile!!:" DISPLAY fatals
|
|
254
|
+
-- !x! ELSE
|
|
255
|
+
-- !x! WRITE "There are no fatal errors."
|
|
256
|
+
-- !x! ENDIF
|
|
257
|
+
-- !x! ELSE
|
|
258
|
+
-- !x! WRITE "There is no error log."
|
|
259
|
+
-- !x! ENDIF
|
|
260
|
+
drop table if exists staging.errorlog cascade;
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
The `PROMPT` metacommand produces a GUI display of the data:
|
|
264
|
+
|
|
265
|
+

|
|
266
|
+
|
|
267
|
+
# Formatting Scripts
|
|
268
|
+
|
|
269
|
+
The `execsql-format` command normalizes execsql script files: it uppercases metacommand keywords, corrects block indentation, and optionally reformats SQL via sqlglot. It is installed automatically with the `execsql2` package.
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Format files in place
|
|
273
|
+
execsql-format --in-place scripts/
|
|
274
|
+
|
|
275
|
+
# Check formatting without writing (useful in CI)
|
|
276
|
+
execsql-format --check scripts/
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
See the [formatter documentation](https://execsql2.readthedocs.io/en/latest/formatter/) for all options.
|
|
280
|
+
|
|
281
|
+
# Templates
|
|
282
|
+
|
|
283
|
+
The `templates/` directory in this repository includes ready-to-use execsql scripts:
|
|
284
|
+
|
|
285
|
+
- **Upsert scripts** (`pg_upsert.sql`, `md_upsert.sql`, `ss_upsert.sql`): Perform merge/upsert operations on multiple tables simultaneously, respecting foreign key order, for PostgreSQL, MySQL/MariaDB, and SQL Server.
|
|
286
|
+
- **Comparison scripts** (`pg_compare.sql`, `md_compare.sql`, `ss_compare.sql`): Compare staging and base tables across multiple dimensions.
|
|
287
|
+
- **Glossary scripts** (`pg_glossary.sql`, `md_glossary.sql`, `ss_glossary.sql`): Produce a glossary of column names and definitions to accompany a database export.
|
|
288
|
+
- **`script_template.sql`**: A framework for new scripts with sections for configuration, logging, and error reporting.
|
|
289
|
+
- **`execsql.conf`**: An annotated configuration file covering all available settings.
|
|
290
|
+
|
|
291
|
+
# Documentation
|
|
292
|
+
|
|
293
|
+
Full documentation, including a complete metacommand reference and 30+ examples, is at [execsql2.readthedocs.io](https://execsql2.readthedocs.io/).
|
|
294
|
+
|
|
295
|
+
# Copyright and License
|
|
296
|
+
|
|
297
|
+
Copyright (c) 2007-2025 R.Dreas Nielsen
|
|
298
|
+
Copyright (c) 2026-present Caleb Grant
|
|
299
|
+
|
|
300
|
+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the [GNU General Public License](http://www.gnu.org/licenses/) for more details.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
execsql/__init__.py,sha256=BIny4bL8uHuSl3gXPqEkIB2FtcexlARjR7IYPwtD9bM,486
|
|
2
|
+
execsql/__main__.py,sha256=HdbK-SAhyUmfB6xINY5AzxdMSxGzWSGEG_2dv42Jn64,315
|
|
3
|
+
execsql/cli.py,sha256=vXK97DZ0HAb_jOJP2qFXAXEtNbfdyA5tnhjY_xdB5bo,41347
|
|
4
|
+
execsql/config.py,sha256=qwhavI1KpU9FnxciE30cqbk8JfOmzrZa3g5IVRDJZlA,33344
|
|
5
|
+
execsql/constants.py,sha256=up8I1sfFg1KaQ-ZgwufDOYbupMgTkPVpHzAdWpi5-BQ,12628
|
|
6
|
+
execsql/exceptions.py,sha256=O68QF4VRdqslGQbTQX0IaRT0EW2s6t_4fdHb0-4sA2Y,8003
|
|
7
|
+
execsql/format.py,sha256=4uNF2MSDBYwZuK9k4wywcUZFU4D_9bMokseOyaCjmGU,11911
|
|
8
|
+
execsql/models.py,sha256=INArNIF_lds_Jv3aXXXFO8Cf1W7G_IjsZDLsVnDlSCs,12427
|
|
9
|
+
execsql/parser.py,sha256=kue_NonM_VLAnfYDqJ_7mXJSfKsTLFLJBOj9pRWACJ0,12689
|
|
10
|
+
execsql/script.py,sha256=6vorNTs1RP90VcbL06bDZQp1_04LBbldT04k5TUzbQY,46852
|
|
11
|
+
execsql/state.py,sha256=INT7eXwO8_drZrngHqq2A4hN8Hrh-JFXELUVuqX4wgY,12385
|
|
12
|
+
execsql/types.py,sha256=aqGX-EFIdWUWt5ofiWQFphzhuYhrAhGH0xtFBTvb1KY,29187
|
|
13
|
+
execsql/db/__init__.py,sha256=jTbuafuKOqYtXFR1wvCOoKK5Lr3l1uErfaIbIr6UywI,1063
|
|
14
|
+
execsql/db/access.py,sha256=4VT-FtKixcHInM9pdKWc7983WSvMXDY32wWBr-iu8uI,15930
|
|
15
|
+
execsql/db/base.py,sha256=gsFUH2SnQQdw0fLVrfzJFuQizSIqq-2XKJRQbZjagfw,23924
|
|
16
|
+
execsql/db/dsn.py,sha256=wFx1CcpXRbMQH5YonMLlfe1qHlSurWdMBrccCfFAuWM,4933
|
|
17
|
+
execsql/db/duckdb.py,sha256=4jSLGn7Hh_Q1eNv7YZJHewxijHO59_DT2y9taSIeGo4,2721
|
|
18
|
+
execsql/db/factory.py,sha256=O8YDNRWBFNcsfN6pnlFb3vuTH3rklfzlpQbAFcMnpGg,4150
|
|
19
|
+
execsql/db/firebird.py,sha256=QF7yVdA1pXeQEsJ4Qg-M6g1FSWFV3PnQDRYF_7FmWm8,7544
|
|
20
|
+
execsql/db/mysql.py,sha256=-miUlWUhyySZgxPPfyI4uYhnQgGhfhzKBu3ibSii_V8,12781
|
|
21
|
+
execsql/db/oracle.py,sha256=6it40w2uXkYOjay46_Ei42Ztbmvmcfky9ovHjrvoD4U,9302
|
|
22
|
+
execsql/db/postgres.py,sha256=ny0ZxN97BVrs2u35adFqYPeHabJb_NSyJt2g-naC7tk,18690
|
|
23
|
+
execsql/db/sqlite.py,sha256=4R5MqoQI4QFAtkEMlOIZmdsRVDuvF_oWYYY2VDWfHIk,9209
|
|
24
|
+
execsql/db/sqlserver.py,sha256=teru36YUAdHl4xx2bupC4o0M1Lp6dAa5xz9pKZ3hGeU,6712
|
|
25
|
+
execsql/exporters/__init__.py,sha256=a679NAJp92e3565fhfqbBIbIT_RdyWQWCJ3-wqJJyYE,525
|
|
26
|
+
execsql/exporters/base.py,sha256=jE2F6KpXwI3YG6iotNyHJc09-rlXwGYPhFVbWngym-I,5735
|
|
27
|
+
execsql/exporters/delimited.py,sha256=3dt0XEB81tzRCtfpyMZeNhBhJ9FVPnaMIC1a6MjS1U0,26886
|
|
28
|
+
execsql/exporters/duckdb.py,sha256=rf0Mg3YWkG2GSlu_wCgNBsQ3Z8m92pfDRh3qAHi8Ado,2677
|
|
29
|
+
execsql/exporters/feather.py,sha256=SVMVNp5Zqf1VN5chFI5hZpcabn45XKnaNfwhU5Rg9SQ,3898
|
|
30
|
+
execsql/exporters/html.py,sha256=0WlY14aPhhht2nrm3s5YDP22sZRTR7lbIYjIwv1GB8Y,8247
|
|
31
|
+
execsql/exporters/json.py,sha256=9mUgBFBbZQtuwgs75WPp3KGMZa0KpZsBhodubX0P1oY,3644
|
|
32
|
+
execsql/exporters/latex.py,sha256=q_3u7whsISdeBcsIeFVEYoACD8g-VsJU-OXPCN5Nb7U,4061
|
|
33
|
+
execsql/exporters/ods.py,sha256=WeM7PtHPn-L0erOyW-puslpG1hb_nQJ5r2J_Oy4JwU8,17064
|
|
34
|
+
execsql/exporters/parquet.py,sha256=Qok-zM-vLMpOh4FsevuL7AM8moawzhsht_DZ3lWmcQ0,976
|
|
35
|
+
execsql/exporters/pretty.py,sha256=lWVd8hWBPHck8xThVPg-GZzRgF74S_X1-LhOXS_Gzos,3122
|
|
36
|
+
execsql/exporters/raw.py,sha256=tS0jp3MIZF_i8VTOkWbFhsNGw8C6aHmPBD8zovtnrQE,1595
|
|
37
|
+
execsql/exporters/sqlite.py,sha256=gzVUilTiVt_4hn8KUk43qk7yeyquYo_zg04f1vOyBQo,2430
|
|
38
|
+
execsql/exporters/templates.py,sha256=3y-2EFvHK_8x5VOND77Xrs91iHyaCra3ody0tOi9jRM,4620
|
|
39
|
+
execsql/exporters/values.py,sha256=DzvdbaS9LQvglrvCkUnTVg9ZIkt8wTO01Q4XgZmV9rk,2176
|
|
40
|
+
execsql/exporters/xls.py,sha256=3A5T9wYWtw0UetqpL4fwYa9xbKiqUbiVigyzDEs_MaA,9039
|
|
41
|
+
execsql/exporters/xml.py,sha256=FUcPW71uG2jpWQF9S_P5cdtvBv4VQJUSUgNlPv-ucWk,1754
|
|
42
|
+
execsql/exporters/zip.py,sha256=Ujp4gD3vfqy8Cq2b1iLFhfDdjcGdibawrxnSoNtCjS8,3463
|
|
43
|
+
execsql/gui/__init__.py,sha256=KnLB-8GuRPBZij4W-sihcA9ORRuLDYoa0p2dCeIzYRg,2001
|
|
44
|
+
execsql/gui/base.py,sha256=gbfCqj3nOMkAcn-GNIIAy7RdPFJ0UMbzOxpDpfoEVxk,6042
|
|
45
|
+
execsql/gui/console.py,sha256=Ln9ixVMLlEK5foHi0t2EywrvTiBqWoPEpp8cnof3eIw,14241
|
|
46
|
+
execsql/gui/desktop.py,sha256=zooMA28FWHndy9Aw242wRzchs1QxYwlGGMsWvn4-EKo,42123
|
|
47
|
+
execsql/gui/tui.py,sha256=n5xzwe1jAsU54jj0PpcBmVfnvfycPVOeiLx07-IfVVk,45948
|
|
48
|
+
execsql/importers/__init__.py,sha256=dDsxSVeQYXBvm9yGqN3QswyGbLWTwt08pvUuRJgZhl4,289
|
|
49
|
+
execsql/importers/base.py,sha256=E9CIzy4O_DKdVB6n3lyxF44M1PL_FdDGynE1wCOtDk0,3983
|
|
50
|
+
execsql/importers/csv.py,sha256=BlMsUlVd6q0hzi-4jmAj76P3Zd_nafhm54sOo_pSKzM,4619
|
|
51
|
+
execsql/importers/feather.py,sha256=oRXdgGsJB_16rc8oewvqKYo2lBe3tivFGufJG7Wvfy0,1698
|
|
52
|
+
execsql/importers/ods.py,sha256=f_OlQpjb49CFUDiC5ypct0SjmxUsFNY5OybETvKmVJw,2709
|
|
53
|
+
execsql/importers/xls.py,sha256=bOsAOt_XRtNVYZVthNAweoH-EArG3s56_MyOzgjBErE,3541
|
|
54
|
+
execsql/metacommands/__init__.py,sha256=Gbf_hQJHFqxdVsChoqeQxKbPv0txK6lSENRCBtsPgPg,65018
|
|
55
|
+
execsql/metacommands/conditions.py,sha256=A-6I_jZ_zsq0CV9k4X5mZ6APg0TnHEahEiZ_0oa-nhc,22423
|
|
56
|
+
execsql/metacommands/connect.py,sha256=Nsm0D91i3RX-R2rzQQ-Br-gULaI6Uvdn9fqb7DOAVfE,14804
|
|
57
|
+
execsql/metacommands/control.py,sha256=iaGK_X1vF18HMEcGOWQuJPG7UfaZFkph2iXkOvf7BQc,7617
|
|
58
|
+
execsql/metacommands/data.py,sha256=Cfb9-vpKQkK-ql8hIgKqMAJhjuA4fgb56vaxqqbo4es,11334
|
|
59
|
+
execsql/metacommands/debug.py,sha256=tIGosPmn4YbQTp67VJK8CmUOvwjiSg2WBRPznKOCKfU,8058
|
|
60
|
+
execsql/metacommands/io.py,sha256=7e6Y37gAbMND0m2Zk-_Szy6lG6jNwUg_9glcPfQs2hA,44860
|
|
61
|
+
execsql/metacommands/prompt.py,sha256=yAs7HNMN38ttxjl5ubxY1u-lE7nkBc5B5uk1G5ksK0c,38093
|
|
62
|
+
execsql/metacommands/script_ext.py,sha256=TUgAldB2LSJAwZrCvDDi804hQ1d9BDQD2GDqHNPVOcM,2280
|
|
63
|
+
execsql/metacommands/system.py,sha256=w6xL3dT7zJ0pVOOckyHQM4SBvCmaX9q_daPlwq4Mi4I,7137
|
|
64
|
+
execsql/utils/__init__.py,sha256=0uR6JwVJQRX3vceByNBduCAf5dd5assKjeqJUWvpZoA,278
|
|
65
|
+
execsql/utils/auth.py,sha256=AVAKsLN4qBlfO8Axz4rmav4IujdM50RgPFZeidGmYqI,6931
|
|
66
|
+
execsql/utils/crypto.py,sha256=RRbrmbwq0NoNWUH4ZjzsI1H42um3d7Ftfoap9Fp0Nl4,3033
|
|
67
|
+
execsql/utils/datetime.py,sha256=WNnU5xXJWKN1dEeeaEX8GzOK0wqDuLwnaVnU7LKT0RI,7666
|
|
68
|
+
execsql/utils/errors.py,sha256=1beWINMdvE0HUJamIlToKOdDZEmIdsIxtfUMTv6l_Ko,6210
|
|
69
|
+
execsql/utils/fileio.py,sha256=zVUZ4y5r60b6LUdxRVa7iziJ9ns_3kqPMkyBePCHvMQ,23321
|
|
70
|
+
execsql/utils/gui.py,sha256=LS2Z8sSwW65QGYHHQBApVDaLaPdB6Eq8aTNn71cPimE,16668
|
|
71
|
+
execsql/utils/mail.py,sha256=Z1t0agMd6zQbB0fJM3aejmpVYTi6PbsPDchqT8pKay0,5628
|
|
72
|
+
execsql/utils/numeric.py,sha256=n9DSZOTJ2gAjUY_S6JZVxpAZ71SKDEFiLwdbE7haymw,1524
|
|
73
|
+
execsql/utils/regex.py,sha256=B6XXlaGAznKarrrrowLcjZ52PbkwAWmZzWz1FlRrUZM,3632
|
|
74
|
+
execsql/utils/strings.py,sha256=YSaPlax1b_EEL3VZAAP508AL2UomCEOYuhriX_pG7Kc,8230
|
|
75
|
+
execsql/utils/timer.py,sha256=1oqmmMU7w0L7zgo_3n7b_7rpoHt0H081zCPFYwrWBlo,1862
|
|
76
|
+
execsql2-2.1.2.data/data/execsql2_extras/READ_ME.rst,sha256=xrseluXaBIw0mec1J5rcNVKIgOqHRCJcbGrCsAay7UI,4848
|
|
77
|
+
execsql2-2.1.2.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
|
|
78
|
+
execsql2-2.1.2.data/data/execsql2_extras/example_config_prompt.sql,sha256=SY3Jxn1qcVm4kPW9xmmTfknHfvURXmeEYTbRjYrjGSw,7487
|
|
79
|
+
execsql2-2.1.2.data/data/execsql2_extras/execsql.conf,sha256=l0DI9CEZhNAqknjNYzYr5GzGtO3NTO4WwlVUJgj3n7M,9515
|
|
80
|
+
execsql2-2.1.2.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
|
|
81
|
+
execsql2-2.1.2.data/data/execsql2_extras/md_compare.sql,sha256=B8Wd7LZ0vnMY2qvA139JIEBkPObgRH2i5xj6PejTQt8,24092
|
|
82
|
+
execsql2-2.1.2.data/data/execsql2_extras/md_glossary.sql,sha256=DJRHcU5NbFpxTTX-IwH3yRlsboj1q6BBGrUAHKn4Cuo,10796
|
|
83
|
+
execsql2-2.1.2.data/data/execsql2_extras/md_upsert.sql,sha256=v_7GbWh_N1mBTmw3gvTrkagOVp2q0KmXvM8hE-DlFxY,112524
|
|
84
|
+
execsql2-2.1.2.data/data/execsql2_extras/pg_compare.sql,sha256=9dWa8hnfy5dVJI-z2iGpd9JzQmI4j2ziMlEdpnr66ro,24352
|
|
85
|
+
execsql2-2.1.2.data/data/execsql2_extras/pg_glossary.sql,sha256=pKjIIDsROAgJq2H-1qNEcRMAWManivcZ_AEVHzUUlic,9908
|
|
86
|
+
execsql2-2.1.2.data/data/execsql2_extras/pg_upsert.sql,sha256=k7AFiGTLBy3nf-qO5QIaZrEYTAKvdxxU3JDLx9jqkzs,108315
|
|
87
|
+
execsql2-2.1.2.data/data/execsql2_extras/script_template.sql,sha256=1Estacb_vm1FgK41k_G9nuduP1yiA-fQ1Kn4Z4mv5Ao,11153
|
|
88
|
+
execsql2-2.1.2.data/data/execsql2_extras/ss_compare.sql,sha256=TsVxWm3cEpR5-EiMYXNhtaY0arSNeKZhsJdHdLA7xeI,24833
|
|
89
|
+
execsql2-2.1.2.data/data/execsql2_extras/ss_glossary.sql,sha256=cLM7nN8JOIu9ZVP9oY9qdSK3hrnWJiDcX6nZmQQbQWI,13065
|
|
90
|
+
execsql2-2.1.2.data/data/execsql2_extras/ss_upsert.sql,sha256=BCqmBykXBF-BpCgOFeG1qhf2XfScKsxPD17wd1hYfHw,120647
|
|
91
|
+
execsql2-2.1.2.dist-info/METADATA,sha256=hf_k-tE3yUQEsbzUOc_bkEhQt-c1D3w-C9geEd0Brw0,14893
|
|
92
|
+
execsql2-2.1.2.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
93
|
+
execsql2-2.1.2.dist-info/entry_points.txt,sha256=sUOxkM-dN1eBGGpSpDLsAaE0yNXYQKWZAfxPOlMkQyk,90
|
|
94
|
+
execsql2-2.1.2.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
|
|
95
|
+
execsql2-2.1.2.dist-info/licenses/NOTICE,sha256=sqVrM73Ys9zfvWC_P797lHfTnoPW_ETeBSrUTFaob0A,339
|
|
96
|
+
execsql2-2.1.2.dist-info/RECORD,,
|