Default repository for execsql.py
Révision | 993b1fdb5d5beac5862fdaebe0e4e391f8f416c4 (tree) |
---|---|
l'heure | 2020-02-07 10:10:26 |
Auteur | Dreas Nielsen <dreas.nielsen@gmai...> |
Commiter | Dreas Nielsen |
Modified so that PROMPT ASK accepts multi-line messages.
@@ -27,12 +27,12 @@ | ||
27 | 27 | # |
28 | 28 | # =============================================================================== |
29 | 29 | |
30 | -__version__ = "1.61.3" | |
30 | +__version__ = "1.61.5" | |
31 | 31 | __vdate = "2020-02-06" |
32 | 32 | |
33 | 33 | primary_vno = 1 |
34 | 34 | secondary_vno = 61 |
35 | -tertiary_vno = 2 | |
35 | +tertiary_vno = 5 | |
36 | 36 | |
37 | 37 | import os |
38 | 38 | import os.path |
@@ -798,7 +798,6 @@ | ||
798 | 798 | time_left = self.maxtime - elapsed_time |
799 | 799 | barlength = 30 |
800 | 800 | bar_left = int(round(barlength * time_left/self.maxtime, 0)) |
801 | - #sys.stdout.write("%s |%s%s|\r" % ("{:8.1f}".format(time_left), "+"*bar_left, "-"*(barlength-bar_left))) | |
802 | 801 | output.write("%s |%s%s|\r" % ("{:8.1f}".format(time_left), "+"*bar_left, "-"*(barlength-bar_left))) |
803 | 802 | |
804 | 803 |
@@ -1245,22 +1244,17 @@ | ||
1245 | 1244 | elif isinstance(item, datetime.datetime): |
1246 | 1245 | self.define_iso_datetime_style() |
1247 | 1246 | tc = odf.table.TableCell(valuetype="date", datevalue=item.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3], stylename="iso_datetime") |
1248 | - #tc.addElement(odf.text.P(text=item.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3])) | |
1249 | 1247 | elif isinstance(item, datetime.date): |
1250 | 1248 | self.define_iso_date_style() |
1251 | 1249 | tc = odf.table.TableCell(valuetype="date", datevalue=item.strftime("%Y-%m-%d"), stylename="iso_date") |
1252 | - #tc.addElement(odf.text.P(text=item.strftime("%Y-%m-%d"))) | |
1253 | 1250 | elif isinstance(item, datetime.time): |
1254 | 1251 | self.define_iso_datetime_style() |
1255 | 1252 | timeval = datetime.datetime(1899, 12, 30, item.hour, item.minute, item.second, item.microsecond, item.tzinfo) |
1256 | 1253 | tc = odf.table.TableCell(timevalue=timeval.strftime("PT%HH%MM%S.%fS"), stylename="iso_datetime") |
1257 | 1254 | tc.addElement(odf.text.P(text=timeval.strftime("%H:%M:%S.%f"))) |
1258 | - #tc = odf.table.TableCell(valuetype="time", value=datetime.datetime(1899,12,30, item.hour, item.minute, item.second, item.microsecond, item.tzinfo)) | |
1259 | 1255 | elif isinstance(item, stringtypes): |
1260 | - #tc = odf.table.TableCell(stringvalue=item) | |
1261 | 1256 | item = item.replace(u'\n', u' ').replace(u'\r', u' ') |
1262 | 1257 | tc = odf.table.TableCell(valuetype="string", stringvalue=item) |
1263 | - #tc.addElement(odf.text.P(text=unicode(item))) | |
1264 | 1258 | else: |
1265 | 1259 | tc = odf.table.TableCell(value=item) |
1266 | 1260 | if item is not None: |
@@ -1433,7 +1427,6 @@ | ||
1433 | 1427 | return u''.join(chr(ord(t)^ord(k)) for t,k in zip(text, itertools.cycle(enckey))) |
1434 | 1428 | def encrypt(self, plaintext): |
1435 | 1429 | random.seed() |
1436 | - #kykey = self.ky.keys()[random.randint(0, len(self.ky.keys())-1)] | |
1437 | 1430 | kykey = list(self.ky)[random.randint(0, len(list(self.ky))-1)] |
1438 | 1431 | kyval = self.ky[kykey] |
1439 | 1432 | noiselen = random.randint(1, 15) |
@@ -1703,12 +1696,10 @@ | ||
1703 | 1696 | elif hasattr(exc_param, 'value') and isinstance(exc_param.value, stringtypes) and len(exc_param.value) > 0: |
1704 | 1697 | exc_message = exc_param.value |
1705 | 1698 | else: |
1706 | - #exc_message = repr(exc_param) | |
1707 | 1699 | exc_message = type(u"")(exc_param) |
1708 | 1700 | try: |
1709 | 1701 | exc_message = type(u"")(exc_message) |
1710 | 1702 | except: |
1711 | - # UnicodeDecode error. 'repr()' will escape bad characters, but also newlines. | |
1712 | 1703 | exc_message = repr(exc_message) |
1713 | 1704 | return sys.exc_info()[0].__name__, exc_message, strace[0][0], xline, strace[0][3] |
1714 | 1705 |
@@ -2792,23 +2783,6 @@ | ||
2792 | 2783 | return "Method %s is not implemented for database %s" % (self.method, self.db_name) |
2793 | 2784 | |
2794 | 2785 | |
2795 | -#class DictRows(object): | |
2796 | -# def __init__(self, cursor, encoding): | |
2797 | -# self.headers = [d[0] for d in cursor.description] | |
2798 | -# self.curs = cursor | |
2799 | -# self.encoding = encoding | |
2800 | -# self.dict = None | |
2801 | -# def __iter__(self): | |
2802 | -# return self | |
2803 | -# def next(self): | |
2804 | -# row = self.curs.fetchone() | |
2805 | -# if row: | |
2806 | -# r = [c.decode(self.encoding) if isinstance(c, stringtypes) else c for c in row] | |
2807 | -# self.dict = dict(zip(self.headers, r)) | |
2808 | -# return self.dict | |
2809 | -# else: | |
2810 | -# raise StopIteration | |
2811 | - | |
2812 | 2786 | class Database(object): |
2813 | 2787 | if sys.version_info < (3,): |
2814 | 2788 | dt_cast = {int: int, long: long, float: float, str: str, unicode: unicode, |
@@ -3044,7 +3018,6 @@ | ||
3044 | 3018 | # Construct INSERT statement. |
3045 | 3019 | columns = [self.type.quoted(col) for col in sel_cols] |
3046 | 3020 | colspec = ",".join(columns) |
3047 | - #paramspec = ",".join([self.paramstr for c in columns]) | |
3048 | 3021 | paramspec = self.paramsubs(len(columns)) |
3049 | 3022 | sql = u"insert into %s (%s) values (%s);" % (sq_name, colspec, paramspec) |
3050 | 3023 | def load_line(line): |
@@ -3388,7 +3361,6 @@ | ||
3388 | 3361 | with io.open(file_name, "rb") as f: |
3389 | 3362 | filedata = f.read() |
3390 | 3363 | sq_name = self.schema_qualified_table_name(schema_name, table_name) |
3391 | - #sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramstr) | |
3392 | 3364 | sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramsubs(1)) |
3393 | 3365 | self.cursor().execute(sql, (pyodbc.Binary(filedata),)) |
3394 | 3366 |
@@ -3460,7 +3432,6 @@ | ||
3460 | 3432 | with io.open(file_name, "rb") as f: |
3461 | 3433 | filedata = f.read() |
3462 | 3434 | sq_name = self.schema_qualified_table_name(schema_name, table_name) |
3463 | - #sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramstr) | |
3464 | 3435 | sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramsubs(1)) |
3465 | 3436 | self.cursor().execute(sql, (pyodbc.Binary(filedata),)) |
3466 | 3437 |
@@ -3606,12 +3577,10 @@ | ||
3606 | 3577 | except: |
3607 | 3578 | self.rollback() |
3608 | 3579 | raise ErrInfo(type="db", command_text=sql, exception_msg=exception_desc(), other_msg=u"Can't load data into table %s from line {%s}" % (sq_name, line)) |
3609 | - #self.commit() | |
3610 | 3580 | def import_entire_file(self, schema_name, table_name, column_name, file_name): |
3611 | 3581 | with io.open(file_name, "rb") as f: |
3612 | 3582 | filedata = f.read() |
3613 | 3583 | sq_name = self.schema_qualified_table_name(schema_name, table_name) |
3614 | - #sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramstr) | |
3615 | 3584 | sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramsubs(1)) |
3616 | 3585 | self.cursor().execute(sql, (pyodbc.Binary(filedata),)) |
3617 | 3586 |
@@ -3770,7 +3739,6 @@ | ||
3770 | 3739 | except: |
3771 | 3740 | self.rollback() |
3772 | 3741 | raise ErrInfo(type="db", command_text=sql_template, exception_msg=exception_desc(), other_msg=u"Import from file into table %s, line {%s}" % (sq_name, line)) |
3773 | - #data_indexes = [csv_file_cols.index(col) for col in import_cols] | |
3774 | 3742 | data_indexes = [csv_file_cols_q.index(col) for col in import_cols] |
3775 | 3743 | paramspec = ",".join(['%s']*len(import_cols)) |
3776 | 3744 | sql_template = u"insert into %s (%s) values (%s);" % (sq_name, input_col_list, paramspec) |
@@ -3785,7 +3753,6 @@ | ||
3785 | 3753 | with io.open(file_name, "rb") as f: |
3786 | 3754 | filedata = f.read() |
3787 | 3755 | sq_name = self.schema_qualified_table_name(schema_name, table_name) |
3788 | - #sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramstr) | |
3789 | 3756 | sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramsubs(1)) |
3790 | 3757 | self.cursor().execute(sql, (psycopg2.Binary(filedata),)) |
3791 | 3758 |
@@ -3873,7 +3840,6 @@ | ||
3873 | 3840 | def column_exists(self, table_name, column_name, schema_name=None): |
3874 | 3841 | curs = self.cursor() |
3875 | 3842 | sql = "select column_name from all_tab_columns where table_name='%s'%s and column_name='%s'" % (table_name, "" if not schema_name else " and owner ='%s'" % schema_name, column_name) |
3876 | - #sql = "select column_name from all_tab_columns where table_name='%s' and column_name='%s'" % (table_name, column_name) | |
3877 | 3843 | try: |
3878 | 3844 | curs.execute(sql) |
3879 | 3845 | except ErrInfo: |
@@ -3902,7 +3868,6 @@ | ||
3902 | 3868 | def view_exists(self, view_name, schema_name=None): |
3903 | 3869 | curs = self.cursor() |
3904 | 3870 | sql = "select view_name from sys.all_views where view_name = '%s'%s" % (view_name, "" if not schema_name else " and owner ='%s'" % schema_name) |
3905 | - #sql = "select view_name from sys.all_views where view_name = '%s'" % view_name | |
3906 | 3871 | try: |
3907 | 3872 | curs.execute(sql) |
3908 | 3873 | except ErrInfo: |
@@ -4072,12 +4037,10 @@ | ||
4072 | 4037 | except: |
4073 | 4038 | self.rollback() |
4074 | 4039 | raise ErrInfo(type="db", command_text=sql, exception_msg=exception_desc(), other_msg=u"Can't load data into table %s from line {%s}" % (sq_name, line)) |
4075 | - #self.commit() | |
4076 | 4040 | def import_entire_file(self, schema_name, table_name, column_name, file_name): |
4077 | 4041 | with io.open(file_name, "rb") as f: |
4078 | 4042 | filedata = f.read() |
4079 | 4043 | sq_name = self.schema_qualified_table_name(schema_name, table_name) |
4080 | - #sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramstr) | |
4081 | 4044 | sql = u"insert into %s (%s) values (%s);" % (sq_name, column_name, self.paramsubs(1)) |
4082 | 4045 | self.cursor().execute(sql, (sqlite3.Binary(filedata), )) |
4083 | 4046 |
@@ -4330,7 +4293,6 @@ | ||
4330 | 4293 | # Firebird will thrown an error if there are foreign keys into the table. |
4331 | 4294 | tablename = self.type.quoted(tablename) |
4332 | 4295 | self.execute(u"DROP TABLE %s;" % tablename) |
4333 | - #self.execute(u"COMMIT;") | |
4334 | 4296 | self.conn.commit() |
4335 | 4297 | |
4336 | 4298 |
@@ -4483,7 +4445,7 @@ | ||
4483 | 4445 | self.item_errors.append(u"%s in position %d." % (errmsg, pos_no)) |
4484 | 4446 | def items(self, delim, qchar): |
4485 | 4447 | # Parses the line into a list of items, breaking it at delimiters that are not |
4486 | - # within quoted stretches. (This is a almost CSV parser, for valid delim and qchar, | |
4448 | + # within quoted stretches. (This is almost a CSV parser, for valid delim and qchar, | |
4487 | 4449 | # except that it does not eliminate quote characters or reduce escaped quotes.) |
4488 | 4450 | self.item_errors = [] |
4489 | 4451 | if qchar is None: |
@@ -5400,8 +5362,8 @@ | ||
5400 | 5362 | |
5401 | 5363 | |
5402 | 5364 | class LocalSubVarSet(SubVarSet): |
5403 | - # A pool of local substitution variables | |
5404 | - # Inherits everything from the base class except the allowed prefix list | |
5365 | + # A pool of local substitution variables. | |
5366 | + # Inherits everything from the base class except the allowed prefix list. | |
5405 | 5367 | # For local variables, only '~' is allowed as a prefix and MUST be present |
5406 | 5368 | def __init__(self): |
5407 | 5369 | SubVarSet.__init__(self) |
@@ -5413,8 +5375,8 @@ | ||
5413 | 5375 | |
5414 | 5376 | |
5415 | 5377 | class ScriptArgSubVarSet(SubVarSet): |
5416 | - # A pool of script argument names | |
5417 | - # Inherits everything from the base class except the allowed prefix list | |
5378 | + # A pool of script argument names. | |
5379 | + # Inherits everything from the base class except the allowed prefix list. | |
5418 | 5380 | # For script arguments, only '#' is allowed as a prefix and MUST be present |
5419 | 5381 | def __init__(self): |
5420 | 5382 | SubVarSet.__init__(self) |
@@ -5481,7 +5443,7 @@ | ||
5481 | 5443 | # Returns the result of the metacommand that was run, or None. |
5482 | 5444 | # Arguments: |
5483 | 5445 | # localvars: a SubVarSet object. |
5484 | - # "commit : not used; included to allow an isomorphic interface with SqlStmt.run(). | |
5446 | + # commit : not used; included to allow an isomorphic interface with SqlStmt.run(). | |
5485 | 5447 | errmsg = "Unknown metacommand" |
5486 | 5448 | cmd = substitute_vars(self.statement, localvars) |
5487 | 5449 | if if_stack.all_true() and varlike.search(cmd): |
@@ -5583,7 +5545,7 @@ | ||
5583 | 5545 | global loop_nest_level |
5584 | 5546 | cmditem = self.cmdlist[self.cmdptr] |
5585 | 5547 | if compiling_loop: |
5586 | - # Don't run this, but save the command or complete the loop and add its commands to the stack. | |
5548 | + # Don't run this command, but save it or complete the loop and add the loop's set of commands to the stack. | |
5587 | 5549 | if cmditem.command_type == 'cmd' and loop_rx.match(cmditem.command.statement): |
5588 | 5550 | loop_nest_level += 1 |
5589 | 5551 | loopcommandstack[-1].add(cmditem) |
@@ -5625,7 +5587,7 @@ | ||
5625 | 5587 | |
5626 | 5588 | |
5627 | 5589 | class CommandListWhileLoop(CommandList): |
5628 | - # Subclass of CommandList() that will loop WHILE a condition is met | |
5590 | + # Subclass of CommandList() that will loop WHILE a condition is met. | |
5629 | 5591 | # Additional argument: |
5630 | 5592 | # loopcondition : A string containing the conditional for continuing the WHILE loop. |
5631 | 5593 | def __init__(self, cmdlist, listname, paramnames, loopcondition): |
@@ -5645,7 +5607,7 @@ | ||
5645 | 5607 | |
5646 | 5608 | |
5647 | 5609 | class CommandListUntilLoop(CommandList): |
5648 | - # Subclass of CommandList() that will loop UNTIL a condition is met | |
5610 | + # Subclass of CommandList() that will loop UNTIL a condition is met. | |
5649 | 5611 | # Additional argument: |
5650 | 5612 | # loopcondition : A string containing the conditional for terminating the UNTIL loop. |
5651 | 5613 | def __init__(self, cmdlist, listname, paramnames, loopcondition): |
@@ -5779,7 +5741,7 @@ | ||
5779 | 5741 | cl.set_paramvals(scriptvarset) |
5780 | 5742 | # If argument expressions were NOT found, confirm that the command list is not expecting named params |
5781 | 5743 | else: |
5782 | - # 'Cause if it IS, there's a problem | |
5744 | + # because if it IS, there's a problem. | |
5783 | 5745 | if cl.paramnames is not None: |
5784 | 5746 | raise ErrInfo("error", other_msg="Missing expected parameters (%s) in call to %s." % (", ".join(cl.paramnames), cl.listname)) |
5785 | 5747 | commandliststack.append(cl) |
@@ -5820,10 +5782,10 @@ | ||
5820 | 5782 | # Sort columns in Tkinter Treeview. From https://stackoverflow.com/questions/1966929/tk-treeview-column-sort#1967793 |
5821 | 5783 | colvals = [(tv.set(k, col), k) for k in tv.get_children()] |
5822 | 5784 | colvals.sort(reverse=reverse) |
5823 | - # rearrange items in sorted positions | |
5785 | + # Rearrange items in sorted positions | |
5824 | 5786 | for index, (val, k) in enumerate(colvals): |
5825 | 5787 | tv.move(k, '', index) |
5826 | - # reverse sort next time | |
5788 | + # Reverse sort next time | |
5827 | 5789 | tv.heading(col, command=lambda: treeview_sort_column(tv, col, not reverse)) |
5828 | 5790 | |
5829 | 5791 | def gui_manager(): |
@@ -7137,7 +7099,6 @@ | ||
7137 | 7099 | self.resp_queue = queue.Queue() |
7138 | 7100 | self.kill_event = threading.Event() |
7139 | 7101 | self.stop_update_event = threading.Event() |
7140 | - #self.console_killed_event = threading.Event() | |
7141 | 7102 | gui_manager_queue.put(GuiSpec(gui_type=GUI_CONSOLE, |
7142 | 7103 | gui_args={"kill_event": self.kill_event, |
7143 | 7104 | "stop_update_event": self.stop_update_event, |
@@ -7178,7 +7139,6 @@ | ||
7178 | 7139 | def __init__(self, title, message, countdown=None): |
7179 | 7140 | # Countdown must be an integer indicating the maximum number of seconds |
7180 | 7141 | # that the UI will be displayed. |
7181 | - #global tk, ttk | |
7182 | 7142 | try: |
7183 | 7143 | import Tkinter as tk |
7184 | 7144 | except: |
@@ -7814,7 +7774,7 @@ | ||
7814 | 7774 | |
7815 | 7775 | |
7816 | 7776 | class CondParser(CondTokens, object): |
7817 | - # Takes a numeric expression string | |
7777 | + # Takes a conditional expression string. | |
7818 | 7778 | def __init__(self, condexpr): |
7819 | 7779 | self.cond_expr = SourceString(condexpr) |
7820 | 7780 | def match_metacommand(self, metacmd): |
@@ -7861,7 +7821,7 @@ | ||
7861 | 7821 | if m1 is not None: |
7862 | 7822 | m1 = self.factor() |
7863 | 7823 | return CondAstNode(self.NOT, m1, None) |
7864 | - # match_any_metacommand returns a tuple consisting of (metacommand, groupdict) | |
7824 | + # Match_any_metacommand -- returns a tuple consisting of (metacommand, groupdict) | |
7865 | 7825 | m1 = self.match_any_metacommand(conditionals) |
7866 | 7826 | if m1 is not None: |
7867 | 7827 | return CondAstNode(self.CONDITIONAL, m1, None) |
@@ -8629,8 +8589,8 @@ | ||
8629 | 8589 | return None |
8630 | 8590 | |
8631 | 8591 | metacommands.append(MetaCommand( |
8632 | - ins_table_rxs(r'^\s*PROMPT\s+ASK\s+"(?P<question>.+)"\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+', r')?\s*$') + | |
8633 | - ins_table_rxs(r"^\s*PROMPT\s+ASK\s+'(?P<question>.+)'\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+", r')?\s*$') + | |
8592 | + ins_table_rxs(r'^\s*PROMPT\s+ASK\s+"(?P<question>[^"]+)"\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+', r')?\s*$') + | |
8593 | + ins_table_rxs(r"^\s*PROMPT\s+ASK\s+'(?P<question>[^']+)'\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+", r')?\s*$') + | |
8634 | 8594 | ins_table_rxs(r'^\s*PROMPT\s+ASK\s+\[(?P<question>[^\]]+)\]\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+', r')?\s*$'), |
8635 | 8595 | x_prompt_ask)) |
8636 | 8596 |
@@ -8807,7 +8767,6 @@ | ||
8807 | 8767 | script, line_no = current_script_line() |
8808 | 8768 | cmd = u"select * from %s;" % sq_name |
8809 | 8769 | colnames, rows = db.select_data(cmd) |
8810 | - #title, message, button_list, selected_button=0, no_cancel=False, column_headers=None, rowset=None, textentry=None | |
8811 | 8770 | enable_gui() |
8812 | 8771 | return_queue = queue.Queue() |
8813 | 8772 | gui_args = {"title": table, |
@@ -8892,7 +8851,6 @@ | ||
8892 | 8851 | exec_log.log_exit_halt(script, line_no, msg) |
8893 | 8852 | exit_now(2, None) |
8894 | 8853 | |
8895 | - | |
8896 | 8854 | metacommands.append(MetaCommand( |
8897 | 8855 | ins_table_rxs(r'^\s*PROMPT\s+ACTION\s+', ins_table_rxs(r'\s+MESSAGE\s+"(?P<message>(.|\n)*)"(?:\s+DISPLAY\s+', r')?(?:\s+COMPACT\s+(?P<compact>\d+))?(?:\s+(?P<continue>CONTINUE))?\s*$', suffix="disp")), |
8898 | 8856 | x_prompt_action)) |
@@ -9401,7 +9359,6 @@ | ||
9401 | 9359 | subvarset.add_substitution(varname, dataval) |
9402 | 9360 | return None |
9403 | 9361 | |
9404 | - | |
9405 | 9362 | metacommands.append(MetaCommand(r'^\s*SUBDATA\s+(?P<match>[+~]?\w+)\s+(?P<datasource>.+)\s*$', x_subdata)) |
9406 | 9363 | |
9407 | 9364 |
@@ -4,7 +4,7 @@ | ||
4 | 4 | long_description = f.read() |
5 | 5 | |
6 | 6 | setuptools.setup(name='execsql', |
7 | - version='1.61.3', | |
7 | + version='1.61.5', | |
8 | 8 | description="Runs a SQL script against a PostgreSQL, MS-Access, SQLite, MS-SQL-Server, MySQL, MariaDB, Firebird, 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. Data can be exported in 13 different formats, including CSV, TSV, ODS, HTML, JSON, LaTeX, and Markdown tables, and using custom templates.", |
9 | 9 | author='Dreas Nielsen', |
10 | 10 | author_email='dreas.nielsen@gmail.com', |