From 8586c774f72defee4c95c7059aa2992e9fead9ef Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Mon, 2 Oct 2023 02:30:07 -0500 Subject: [PATCH 01/37] Outline of script file for upgrading databases --- bin/upgrade-db | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 bin/upgrade-db diff --git a/bin/upgrade-db b/bin/upgrade-db new file mode 100644 index 0000000..e26b0db --- /dev/null +++ b/bin/upgrade-db @@ -0,0 +1,54 @@ +#! /usr/bin/env python + +import sqlite3 + + +def main() -> None: + import sys + from optparse import OptionParser + import argparse + + parser = argparse.ArgumentParser(description="Analyze a logpyle database.") + parser.add_argument("dbfiles", nargs="+", type=str, + help="database file(s) to read") + parser.add_argument("--suffix", type=str, + help="""a suffix to append to the filename of the + newly upgraded database file""") + + args = parser.parse_args() + + if not args.suffix: + args.suffix = "_upgrade" + + for dbfile in args.dbfiles: + new_db = upgrade_db(dbfile, suffix=args.suffix) + + new_db.commit() + + +def upgrade_db(dbfile: str, suffix: str) -> sqlite3.Connection: + + old_conn = sqlite3.connect(dbfile) + + desc = old_conn.execute("select * from quantities").description + print(desc) + + # upgrade from V1/V0 + if (len(old_conn.execute("select * from quantities").description) == 0): + pass + + # upgrade from V2 + if (len(old_conn.execute("select * from quantities").description) == 0): + pass + + # seperate the filename and the extention + filename, file_ext = dbfile.rsplit('.', 1) + new_conn = sqlite3.connect(filename + suffix + file_ext) + + # insert and modify new_conn data + + return new_conn + + +if __name__ == "__main__": + main() From 3c8d4368c92ff9855ad4758cef26fe88d7231224 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Mon, 2 Oct 2023 02:34:27 -0500 Subject: [PATCH 02/37] arg description update --- bin/upgrade-db | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/upgrade-db b/bin/upgrade-db index e26b0db..b5f8098 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -8,7 +8,7 @@ def main() -> None: from optparse import OptionParser import argparse - parser = argparse.ArgumentParser(description="Analyze a logpyle database.") + parser = argparse.ArgumentParser(description="Upgrade an existing database file to version 3") parser.add_argument("dbfiles", nargs="+", type=str, help="database file(s) to read") parser.add_argument("--suffix", type=str, From 5536ccebd5b32fbaa4b7400d652849d99665062a Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Tue, 3 Oct 2023 16:04:49 -0500 Subject: [PATCH 03/37] Untested, but upgrades database. Currently takes in a suffix (which could be the empty string if the file should be replaced) and outputs the upgraded database with the suffix appended to the filename (before the file extension) --- bin/upgrade-db | 64 ++++++++++++++++++++++++++++++++++++-------------- setup.py | 1 + 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/bin/upgrade-db b/bin/upgrade-db index b5f8098..cdd3e6c 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -4,11 +4,10 @@ import sqlite3 def main() -> None: - import sys - from optparse import OptionParser import argparse - parser = argparse.ArgumentParser(description="Upgrade an existing database file to version 3") + parser = argparse.ArgumentParser(description="Upgrade an existing database\ + file to version 3") parser.add_argument("dbfiles", nargs="+", type=str, help="database file(s) to read") parser.add_argument("--suffix", type=str, @@ -21,31 +20,62 @@ def main() -> None: args.suffix = "_upgrade" for dbfile in args.dbfiles: - new_db = upgrade_db(dbfile, suffix=args.suffix) + new_db = upgrade_gathered_db(dbfile, suffix=args.suffix) new_db.commit() -def upgrade_db(dbfile: str, suffix: str) -> sqlite3.Connection: +def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: old_conn = sqlite3.connect(dbfile) - desc = old_conn.execute("select * from quantities").description - print(desc) - - # upgrade from V1/V0 - if (len(old_conn.execute("select * from quantities").description) == 0): - pass - - # upgrade from V2 - if (len(old_conn.execute("select * from quantities").description) == 0): - pass + tmp = old_conn.execute("select * from warnings").description + warning_columns = [col[0] for col in tmp] + print(warning_columns) # seperate the filename and the extention filename, file_ext = dbfile.rsplit('.', 1) - new_conn = sqlite3.connect(filename + suffix + file_ext) - # insert and modify new_conn data + new_conn_name = filename + suffix + "." + file_ext + + with open(dbfile, 'rb') as f: + with open(new_conn_name, 'wb') as f1: + f1.write(f.read()) + + new_conn = sqlite3.connect(new_conn_name) + + print(f"Creating new Database: {new_conn_name}, a clone of {dbfile}") + + print(f"Upgrading {new_conn_name} to schema version 3") + + # ensure that warnings table has unixtime column + if ('unixtime' not in warning_columns): + print("Adding a unixtime column in the warnings table") + new_conn.execute(""" + ALTER TABLE warnings + ADD unixtime integer; + """) + + # ensure that warnings table has rank column + if ('rank' not in warning_columns): + print("Adding a rank column in the warnings table") + new_conn.execute(""" + ALTER TABLE warnings + ADD rank integer; + """) + + print("Creating a logging table") + new_conn.execute(""" + CREATE TABLE IF NOT EXISTS logging ( + run_id integer, + rank integer, + step integer, + unixtime integer, + level text, + message text, + filename text, + lineno integer + )""") return new_conn diff --git a/setup.py b/setup.py index e537b8f..6ad16c4 100644 --- a/setup.py +++ b/setup.py @@ -50,6 +50,7 @@ "bin/runalyzer-gather", "bin/runalyzer", "bin/htmlalyzer", + "bin/upgrade-db", ], author="Andreas Kloeckner", From fd49b2fecea0994896bf4c1a7e7eef737a292f68 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Tue, 3 Oct 2023 16:13:12 -0500 Subject: [PATCH 04/37] Removed single quotes --- bin/upgrade-db | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/upgrade-db b/bin/upgrade-db index cdd3e6c..e3d5508 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -34,12 +34,12 @@ def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: print(warning_columns) # seperate the filename and the extention - filename, file_ext = dbfile.rsplit('.', 1) + filename, file_ext = dbfile.rsplit(".", 1) new_conn_name = filename + suffix + "." + file_ext - with open(dbfile, 'rb') as f: - with open(new_conn_name, 'wb') as f1: + with open(dbfile, "rb") as f: + with open(new_conn_name, "wb") as f1: f1.write(f.read()) new_conn = sqlite3.connect(new_conn_name) @@ -49,7 +49,7 @@ def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: print(f"Upgrading {new_conn_name} to schema version 3") # ensure that warnings table has unixtime column - if ('unixtime' not in warning_columns): + if ("unixtime" not in warning_columns): print("Adding a unixtime column in the warnings table") new_conn.execute(""" ALTER TABLE warnings @@ -57,7 +57,7 @@ def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: """) # ensure that warnings table has rank column - if ('rank' not in warning_columns): + if ("rank" not in warning_columns): print("Adding a rank column in the warnings table") new_conn.execute(""" ALTER TABLE warnings From 5ccf6452331ce7d6c75aedbaf5c2ec6a7a361544 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 5 Oct 2023 10:52:25 -0500 Subject: [PATCH 05/37] Changed default value to show column was not present at time of creation --- bin/upgrade-db | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/upgrade-db b/bin/upgrade-db index e3d5508..84bea76 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -53,7 +53,7 @@ def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: print("Adding a unixtime column in the warnings table") new_conn.execute(""" ALTER TABLE warnings - ADD unixtime integer; + ADD unixtime integer DEFAULT -1; """) # ensure that warnings table has rank column @@ -61,10 +61,10 @@ def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: print("Adding a rank column in the warnings table") new_conn.execute(""" ALTER TABLE warnings - ADD rank integer; + ADD rank integer DEFAULT -1; """) - print("Creating a logging table") + print("Ensuring a logging table exists") new_conn.execute(""" CREATE TABLE IF NOT EXISTS logging ( run_id integer, From 9c2ae8185328e48d3563ea9dac3f97f8e3f98438 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 9 Nov 2023 11:59:53 -0600 Subject: [PATCH 06/37] Added test for upgrading database from V2 to V3 --- .github/workflows/ci.yaml | 38 ++++++++++++++++++++++++++++++++++++++ bin/upgrade-db | 13 ++++++------- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5768724..1d61932 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -211,3 +211,41 @@ jobs: # open html after being built htmlalyzer -b + upgrade-db: + name: Upgrade-Database + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Upgrade V2 to V3 + run: | + pip install -e . + + # test default name + if [ -f .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite ] ; then + rm .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite + fi + upgrade-db .github/flame1d_lazy_2021.10.21-07.26.58.sqlite + + # runalyzer flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + + + # test custom name + if [ -f .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite ] ; then + rm .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite + fi + upgrade-db .github/flame1d_lazy_2021.10.21-07.26.58.sqlite --suffix '_new' + + # runalyzer flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' diff --git a/bin/upgrade-db b/bin/upgrade-db index 84bea76..f624b9d 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -1,6 +1,7 @@ -#! /usr/bin/env python +#!/usr/bin/env python import sqlite3 +import shutil def main() -> None: @@ -20,6 +21,7 @@ def main() -> None: args.suffix = "_upgrade" for dbfile in args.dbfiles: + # here we do assume we have a gathered dbfile new_db = upgrade_gathered_db(dbfile, suffix=args.suffix) new_db.commit() @@ -31,16 +33,13 @@ def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: tmp = old_conn.execute("select * from warnings").description warning_columns = [col[0] for col in tmp] - print(warning_columns) # seperate the filename and the extention filename, file_ext = dbfile.rsplit(".", 1) new_conn_name = filename + suffix + "." + file_ext - with open(dbfile, "rb") as f: - with open(new_conn_name, "wb") as f1: - f1.write(f.read()) + shutil.copy(dbfile, new_conn_name) new_conn = sqlite3.connect(new_conn_name) @@ -53,7 +52,7 @@ def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: print("Adding a unixtime column in the warnings table") new_conn.execute(""" ALTER TABLE warnings - ADD unixtime integer DEFAULT -1; + ADD unixtime integer DEFAULT NULL; """) # ensure that warnings table has rank column @@ -61,7 +60,7 @@ def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: print("Adding a rank column in the warnings table") new_conn.execute(""" ALTER TABLE warnings - ADD rank integer DEFAULT -1; + ADD rank integer DEFAULT NULL; """) print("Ensuring a logging table exists") From e819425100b3432b4d7994646992ed63f24ccce3 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 9 Nov 2023 12:06:43 -0600 Subject: [PATCH 07/37] Fixed flake8 and simplified upgrade-db suffix logic --- .../flame1d_lazy_2021.10.21-07.26.58.sqlite | Bin 0 -> 135168 bytes bin/upgrade-db | 7 +++---- 2 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 .github/flame1d_lazy_2021.10.21-07.26.58.sqlite diff --git a/.github/flame1d_lazy_2021.10.21-07.26.58.sqlite b/.github/flame1d_lazy_2021.10.21-07.26.58.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..c3960f93616275c105dc26feb28fe689a7375047 GIT binary patch literal 135168 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 literal 0 HcmV?d00001 diff --git a/bin/upgrade-db b/bin/upgrade-db index f624b9d..a9975b6 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -1,7 +1,7 @@ #!/usr/bin/env python -import sqlite3 import shutil +import sqlite3 def main() -> None: @@ -17,12 +17,11 @@ def main() -> None: args = parser.parse_args() - if not args.suffix: - args.suffix = "_upgrade" + suffix = args.suffix or "_upgrade" for dbfile in args.dbfiles: # here we do assume we have a gathered dbfile - new_db = upgrade_gathered_db(dbfile, suffix=args.suffix) + new_db = upgrade_gathered_db(dbfile, suffix=suffix) new_db.commit() From 8d51e7aeebc705233b4eb611a520f8a6a0d82a34 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 9 Nov 2023 13:42:10 -0600 Subject: [PATCH 08/37] Upgrade-db supports ungathered files, and overwrite param added --- .github/workflows/ci.yaml | 4 ++-- bin/upgrade-db | 42 +++++++++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 910ad84..e9e2e3d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -258,7 +258,7 @@ jobs: run: | pip install -e . - # test default name + # test gathered default name if [ -f .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite ] ; then rm .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite fi @@ -271,7 +271,7 @@ jobs: runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' - # test custom name + # test gathered custom name if [ -f .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite ] ; then rm .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite fi diff --git a/bin/upgrade-db b/bin/upgrade-db index a9975b6..520d940 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -11,38 +11,60 @@ def main() -> None: file to version 3") parser.add_argument("dbfiles", nargs="+", type=str, help="database file(s) to read") - parser.add_argument("--suffix", type=str, + parser.add_argument("--overwrite", action="store_true", + help="""overwrite the passed in database file""") + parser.add_argument("--suffix", type=str, required=False, help="""a suffix to append to the filename of the newly upgraded database file""") args = parser.parse_args() + if args.overwrite and args.suffix: + raise argparse.ArgumentError( + argument=None, + message="Cannot overwrite file and use a suffix" + ) + + if args.suffix == "": + raise NameError("Specify non-empty suffix, " + "overwriting db files is performed with " + "the flag '--overwrite'") + suffix = args.suffix or "_upgrade" for dbfile in args.dbfiles: - # here we do assume we have a gathered dbfile - new_db = upgrade_gathered_db(dbfile, suffix=suffix) + new_db = upgrade_db( + dbfile, suffix=suffix, overwrite=args.overwrite + ) new_db.commit() -def upgrade_gathered_db(dbfile: str, suffix: str) -> sqlite3.Connection: +def upgrade_db( + dbfile: str, suffix: str, overwrite: bool + ) -> sqlite3.Connection: old_conn = sqlite3.connect(dbfile) tmp = old_conn.execute("select * from warnings").description warning_columns = [col[0] for col in tmp] - # seperate the filename and the extention - filename, file_ext = dbfile.rsplit(".", 1) + if overwrite: + new_conn_name = dbfile + new_conn = old_conn + print(f"Overwriting Database: {new_conn_name}") + + else: + # seperate the filename and the extention + filename, file_ext = dbfile.rsplit(".", 1) - new_conn_name = filename + suffix + "." + file_ext + new_conn_name = filename + suffix + "." + file_ext - shutil.copy(dbfile, new_conn_name) + shutil.copy(dbfile, new_conn_name) - new_conn = sqlite3.connect(new_conn_name) + new_conn = sqlite3.connect(new_conn_name) - print(f"Creating new Database: {new_conn_name}, a clone of {dbfile}") + print(f"Creating new Database: {new_conn_name}, a clone of {dbfile}") print(f"Upgrading {new_conn_name} to schema version 3") From dd88c900626b1546a29491e0262aaa925b46e843 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 9 Nov 2023 13:48:23 -0600 Subject: [PATCH 09/37] Small comments in upgrade-db --- bin/upgrade-db | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/upgrade-db b/bin/upgrade-db index 520d940..5ddf713 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -44,12 +44,14 @@ def upgrade_db( dbfile: str, suffix: str, overwrite: bool ) -> sqlite3.Connection: + # original db files old_conn = sqlite3.connect(dbfile) tmp = old_conn.execute("select * from warnings").description warning_columns = [col[0] for col in tmp] if overwrite: + # simply perform modifications on old connection new_conn_name = dbfile new_conn = old_conn print(f"Overwriting Database: {new_conn_name}") From 840f9570693a76fb7e6ce959d603c48a06bc80be Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 9 Nov 2023 14:26:13 -0600 Subject: [PATCH 10/37] Added upgrade-db test for ungathered files in CI --- .github/log.sqlite | Bin 0 -> 118784 bytes .github/workflows/ci.yaml | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 .github/log.sqlite diff --git a/.github/log.sqlite b/.github/log.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..9d8e45ae9dafc34da76e81fc6b6bc1198df8b43b GIT binary patch literal 118784 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 JztjHze*l}a4r~Ab literal 0 HcmV?d00001 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e9e2e3d..0bc505a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -258,13 +258,25 @@ jobs: run: | pip install -e . + # test ungathered default name + if [ -f .github/log_upgrade.sqlite ] ; then + rm .github/log_upgrade.sqlite + fi + upgrade-db .github/log.sqlite + + runalyzer log_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/log_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' + runalyzer .github/log_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' + runalyzer .github/log_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/log_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + # test gathered default name if [ -f .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite ] ; then rm .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite fi upgrade-db .github/flame1d_lazy_2021.10.21-07.26.58.sqlite - # runalyzer flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' @@ -277,7 +289,7 @@ jobs: fi upgrade-db .github/flame1d_lazy_2021.10.21-07.26.58.sqlite --suffix '_new' - # runalyzer flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' From 8ca0160558377f9f6972faea265736dd69d3ac4d Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 9 Nov 2023 14:32:08 -0600 Subject: [PATCH 11/37] Fixed old print statements in CI --- .github/workflows/ci.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0bc505a..cc9b0a6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -264,7 +264,7 @@ jobs: fi upgrade-db .github/log.sqlite - runalyzer log_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/log_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' runalyzer .github/log_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' runalyzer .github/log_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' runalyzer .github/log_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' @@ -276,7 +276,7 @@ jobs: fi upgrade-db .github/flame1d_lazy_2021.10.21-07.26.58.sqlite - runalyzer flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' @@ -289,7 +289,7 @@ jobs: fi upgrade-db .github/flame1d_lazy_2021.10.21-07.26.58.sqlite --suffix '_new' - runalyzer flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' From a7473df2a3202dcc6d82265a5177a3932105ad0d Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 16 Nov 2023 08:48:28 -0600 Subject: [PATCH 12/37] Renamed stored log version files --- .github/workflows/ci.yaml | 54 ++++++------- .../log_gathered_v2.sqlite} | Bin .../log_ungathered_v3.sqlite} | Bin bin/upgrade-db | 67 +---------------- logpyle/upgrade_db.py | 71 ++++++++++++++++++ 5 files changed, 99 insertions(+), 93 deletions(-) rename .github/{flame1d_lazy_2021.10.21-07.26.58.sqlite => workflows/log_gathered_v2.sqlite} (100%) rename .github/{log.sqlite => workflows/log_ungathered_v3.sqlite} (100%) create mode 100644 logpyle/upgrade_db.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cc9b0a6..a5291f2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -259,38 +259,38 @@ jobs: pip install -e . # test ungathered default name - if [ -f .github/log_upgrade.sqlite ] ; then - rm .github/log_upgrade.sqlite + if [ -f .github/workflows/log_ungathered_v3_upgrade.sqlite ] ; then + rm .github/workflows/log_ungathered_v3_upgrade.sqlite fi - upgrade-db .github/log.sqlite + upgrade-db .github/workflows/log_ungathered_v3.sqlite - runalyzer .github/log_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' - runalyzer .github/log_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' - runalyzer .github/log_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' - runalyzer .github/log_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' - runalyzer .github/log_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' # test gathered default name - if [ -f .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite ] ; then - rm .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite - fi - upgrade-db .github/flame1d_lazy_2021.10.21-07.26.58.sqlite + # if [ -f .github/workflows/log_gathered_v2_upgrade.sqlite ] ; then + # rm .github/workflows/log_gathered_v2_upgrade.sqlite + # fi + upgrade-db .github/workflows/log_gathered_v2.sqlite - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' # test gathered custom name - if [ -f .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite ] ; then - rm .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite - fi - upgrade-db .github/flame1d_lazy_2021.10.21-07.26.58.sqlite --suffix '_new' - - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' - runalyzer .github/flame1d_lazy_2021.10.21-07.26.58_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + # if [ -f .github/workflows/log_gathered_v2_new.sqlite ] ; then + # rm .github/workflows/log_gathered_v2_new.sqlite + # fi + upgrade-db .github/workflows/log_gathered_v2.sqlite --suffix '_new' + + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' diff --git a/.github/flame1d_lazy_2021.10.21-07.26.58.sqlite b/.github/workflows/log_gathered_v2.sqlite similarity index 100% rename from .github/flame1d_lazy_2021.10.21-07.26.58.sqlite rename to .github/workflows/log_gathered_v2.sqlite diff --git a/.github/log.sqlite b/.github/workflows/log_ungathered_v3.sqlite similarity index 100% rename from .github/log.sqlite rename to .github/workflows/log_ungathered_v3.sqlite diff --git a/bin/upgrade-db b/bin/upgrade-db index 5ddf713..4dce095 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -1,11 +1,9 @@ #!/usr/bin/env python -import shutil -import sqlite3 - def main() -> None: import argparse + from logpyle.upgrade_db import upgrade_db parser = argparse.ArgumentParser(description="Upgrade an existing database\ file to version 3") @@ -39,68 +37,5 @@ def main() -> None: new_db.commit() - -def upgrade_db( - dbfile: str, suffix: str, overwrite: bool - ) -> sqlite3.Connection: - - # original db files - old_conn = sqlite3.connect(dbfile) - - tmp = old_conn.execute("select * from warnings").description - warning_columns = [col[0] for col in tmp] - - if overwrite: - # simply perform modifications on old connection - new_conn_name = dbfile - new_conn = old_conn - print(f"Overwriting Database: {new_conn_name}") - - else: - # seperate the filename and the extention - filename, file_ext = dbfile.rsplit(".", 1) - - new_conn_name = filename + suffix + "." + file_ext - - shutil.copy(dbfile, new_conn_name) - - new_conn = sqlite3.connect(new_conn_name) - - print(f"Creating new Database: {new_conn_name}, a clone of {dbfile}") - - print(f"Upgrading {new_conn_name} to schema version 3") - - # ensure that warnings table has unixtime column - if ("unixtime" not in warning_columns): - print("Adding a unixtime column in the warnings table") - new_conn.execute(""" - ALTER TABLE warnings - ADD unixtime integer DEFAULT NULL; - """) - - # ensure that warnings table has rank column - if ("rank" not in warning_columns): - print("Adding a rank column in the warnings table") - new_conn.execute(""" - ALTER TABLE warnings - ADD rank integer DEFAULT NULL; - """) - - print("Ensuring a logging table exists") - new_conn.execute(""" - CREATE TABLE IF NOT EXISTS logging ( - run_id integer, - rank integer, - step integer, - unixtime integer, - level text, - message text, - filename text, - lineno integer - )""") - - return new_conn - - if __name__ == "__main__": main() diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py new file mode 100644 index 0000000..689602b --- /dev/null +++ b/logpyle/upgrade_db.py @@ -0,0 +1,71 @@ +import shutil +import sqlite3 + + +def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: + tmp = conn.execute("select * from warnings").description + warning_columns = [col[0] for col in tmp] + + # ensure that warnings table has unixtime column + if ("unixtime" not in warning_columns): + print("Adding a unixtime column in the warnings table") + conn.execute(""" + ALTER TABLE warnings + ADD unixtime integer DEFAULT NULL; + """) + + # ensure that warnings table has rank column + if ("rank" not in warning_columns): + print("Adding a rank column in the warnings table") + conn.execute(""" + ALTER TABLE warnings + ADD rank integer DEFAULT NULL; + """) + + print("Ensuring a logging table exists") + conn.execute(""" + CREATE TABLE IF NOT EXISTS logging ( + run_id integer, + rank integer, + step integer, + unixtime integer, + level text, + message text, + filename text, + lineno integer + )""") + return conn + + +def upgrade_db( + dbfile: str, suffix: str, overwrite: bool + ) -> sqlite3.Connection: + + # original db files + old_conn = sqlite3.connect(dbfile) + + if overwrite: + # simply perform modifications on old connection + new_conn_name = dbfile + new_conn = old_conn + print(f"Overwriting Database: {new_conn_name}") + + else: + # seperate the filename and the extention + filename, file_ext = dbfile.rsplit(".", 1) + + new_conn_name = filename + suffix + "." + file_ext + + shutil.copy(dbfile, new_conn_name) + + new_conn = sqlite3.connect(new_conn_name) + + print(f"Creating new Database: {new_conn_name}, a clone of {dbfile}") + + print(f"Upgrading {new_conn_name} to schema version 3") + + new_conn = upgrade_conn(new_conn) + + old_conn.close() + + return new_conn From c159b1f89b39acb1bffaddf678a5505b2ad1dd5c Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 16 Nov 2023 10:16:41 -0600 Subject: [PATCH 13/37] Isorted upgrade-db --- bin/upgrade-db | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/upgrade-db b/bin/upgrade-db index 4dce095..253ef6e 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -3,6 +3,7 @@ def main() -> None: import argparse + from logpyle.upgrade_db import upgrade_db parser = argparse.ArgumentParser(description="Upgrade an existing database\ From 194ab42c21056e473ca243728e856be656a63302 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 16 Nov 2023 11:16:55 -0600 Subject: [PATCH 14/37] Autogather can be disabled --- .github/workflows/ci.yaml | 32 ++++++++++++++------- .github/workflows/log_gathered_v3.sqlite | Bin 0 -> 229376 bytes .github/workflows/log_ungathered_v2.sqlite | Bin 0 -> 53248 bytes bin/runalyzer | 16 +++++++++-- logpyle/runalyzer.py | 11 +++++-- logpyle/upgrade_db.py | 2 ++ 6 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/log_gathered_v3.sqlite create mode 100644 .github/workflows/log_ungathered_v2.sqlite diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a5291f2..81f25df 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -258,10 +258,7 @@ jobs: run: | pip install -e . - # test ungathered default name - if [ -f .github/workflows/log_ungathered_v3_upgrade.sqlite ] ; then - rm .github/workflows/log_ungathered_v3_upgrade.sqlite - fi + # test ungathered_v3 default name upgrade-db .github/workflows/log_ungathered_v3.sqlite runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' @@ -270,10 +267,26 @@ jobs: runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' - # test gathered default name - # if [ -f .github/workflows/log_gathered_v2_upgrade.sqlite ] ; then - # rm .github/workflows/log_gathered_v2_upgrade.sqlite - # fi + # test gathered_v3 default name + upgrade-db .github/workflows/log_gathered_v3.sqlite + + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + + # test ungathered_v2 default name + upgrade-db .github/workflows/log_ungathered_v2.sqlite + + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + + + # test gathered_v2 default name upgrade-db .github/workflows/log_gathered_v2.sqlite runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' @@ -284,9 +297,6 @@ jobs: # test gathered custom name - # if [ -f .github/workflows/log_gathered_v2_new.sqlite ] ; then - # rm .github/workflows/log_gathered_v2_new.sqlite - # fi upgrade-db .github/workflows/log_gathered_v2.sqlite --suffix '_new' runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' diff --git a/.github/workflows/log_gathered_v3.sqlite b/.github/workflows/log_gathered_v3.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..0ebb8785df17b5ca1621eb3bf4b6ad89cf62564c GIT binary patch literal 229376 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 literal 0 HcmV?d00001 diff --git a/.github/workflows/log_ungathered_v2.sqlite b/.github/workflows/log_ungathered_v2.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..e218ef518e9826e184c114691cfeb2f65530af5e GIT binary patch literal 53248 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 OGZjEGWS0If8UF+Ii8=NF literal 0 HcmV?d00001 diff --git a/bin/runalyzer b/bin/runalyzer index c0b5e2b..e21dc30 100755 --- a/bin/runalyzer +++ b/bin/runalyzer @@ -16,6 +16,8 @@ def main() -> None: help="database file(s) to read") parser.add_argument("--script", type=str, help="script file to read") + parser.add_argument("--nogather", action="store_true", + help="do not automatically gather files") args = parser.parse_args() from logpyle.runalyzer import make_runalyzer_symbols, make_wrapped_db @@ -27,16 +29,24 @@ def main() -> None: do_mangle = not args.nomangle + gather = not args.nogather + if args.script: - db = make_wrapped_db(args.dbfiles, mangle=do_mangle, interactive=False) + db = make_wrapped_db( + args.dbfiles, mangle=do_mangle, interactive=False, + gather=gather) exec(compile(open(args.script).read(), args.script, "exec"), make_runalyzer_symbols(db)) elif args.commands: - db = make_wrapped_db(args.dbfiles, mangle=do_mangle, interactive=False) + db = make_wrapped_db( + args.dbfiles, mangle=do_mangle, interactive=False, + gather=gather) exec(compile(args.commands, "--commands", "exec"), make_runalyzer_symbols(db)) else: - db = make_wrapped_db(args.dbfiles, mangle=do_mangle, interactive=True) + db = make_wrapped_db( + args.dbfiles, mangle=do_mangle, interactive=True, + gather=gather) from logpyle.runalyzer import RunalyzerConsole cons = RunalyzerConsole(db) cons.interact("Runalyzer running on Python %s\n" diff --git a/logpyle/runalyzer.py b/logpyle/runalyzer.py index 6e8f291..825c011 100644 --- a/logpyle/runalyzer.py +++ b/logpyle/runalyzer.py @@ -506,8 +506,15 @@ def auto_gather(filenames: List[str]) -> sqlite3.Connection: # {{{ main program -def make_wrapped_db(filenames: List[str], interactive: bool, mangle: bool) -> RunDB: - db = auto_gather(filenames) +def make_wrapped_db( + filenames: List[str], interactive: bool, + mangle: bool, gather: bool = True + ) -> RunDB: + if gather: + db = auto_gather(filenames) + else: + assert len(filenames) == 1, "Enable autogather to support multiple infiles" + db = sqlite3.connect(filenames[0]) db.create_aggregate("stddev", 1, StdDeviation) # type: ignore[arg-type] db.create_aggregate("var", 1, Variance) db.create_aggregate("norm1", 1, Norm1) # type: ignore[arg-type] diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 689602b..701cb54 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -15,6 +15,8 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: """) # ensure that warnings table has rank column + # nowhere to grab the rank of the process that generated + # the warning if ("rank" not in warning_columns): print("Adding a rank column in the warnings table") conn.execute(""" From b7d4557f8a50b1975223d1abe5015ffb0b20d8cd Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 16 Nov 2023 11:31:28 -0600 Subject: [PATCH 15/37] Upgrade-db now does not add a run-id col to un-gathered files --- .github/workflows/ci.yaml | 50 +++++++++++++++++++-------------------- logpyle/upgrade_db.py | 46 ++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 81f25df..693d271 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -261,46 +261,46 @@ jobs: # test ungathered_v3 default name upgrade-db .github/workflows/log_ungathered_v3.sqlite - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather # test gathered_v3 default name upgrade-db .github/workflows/log_gathered_v3.sqlite - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather # test ungathered_v2 default name upgrade-db .github/workflows/log_ungathered_v2.sqlite - runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' - runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' - runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' - runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' - runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather # test gathered_v2 default name upgrade-db .github/workflows/log_gathered_v2.sqlite - runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' - runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' - runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' - runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' - runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather # test gathered custom name upgrade-db .github/workflows/log_gathered_v2.sqlite --suffix '_new' - runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' - runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' - runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' - runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' - runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 701cb54..04396ef 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -6,6 +6,17 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: tmp = conn.execute("select * from warnings").description warning_columns = [col[0] for col in tmp] + # check if any of the provided files have been gathered + gathered = False + # get a list of tables with the name of 'runs' + res = list(conn.execute(""" + SELECT name + FROM sqlite_master + WHERE type='table' AND name='runs' + """)) + if len(res) == 1: + gathered = True + # ensure that warnings table has unixtime column if ("unixtime" not in warning_columns): print("Adding a unixtime column in the warnings table") @@ -25,17 +36,30 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: """) print("Ensuring a logging table exists") - conn.execute(""" - CREATE TABLE IF NOT EXISTS logging ( - run_id integer, - rank integer, - step integer, - unixtime integer, - level text, - message text, - filename text, - lineno integer - )""") + if gathered: + conn.execute(""" + CREATE TABLE IF NOT EXISTS logging ( + run_id integer, + rank integer, + step integer, + unixtime integer, + level text, + message text, + filename text, + lineno integer + )""") + else: + conn.execute(""" + CREATE TABLE IF NOT EXISTS logging ( + rank integer, + step integer, + unixtime integer, + level text, + message text, + filename text, + lineno integer + )""") + return conn From 5ca70c5dae649471bad2f6703949b0d6478fcf50 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 16 Nov 2023 19:00:51 -0600 Subject: [PATCH 16/37] Refactoring SQL of upgrade-db --- bin/upgrade-db | 5 +-- logpyle/runalyzer.py | 25 ++++++++------ logpyle/upgrade_db.py | 76 ++++++++++++++++++++----------------------- 3 files changed, 51 insertions(+), 55 deletions(-) diff --git a/bin/upgrade-db b/bin/upgrade-db index 253ef6e..11dd72b 100644 --- a/bin/upgrade-db +++ b/bin/upgrade-db @@ -32,11 +32,8 @@ def main() -> None: suffix = args.suffix or "_upgrade" for dbfile in args.dbfiles: - new_db = upgrade_db( - dbfile, suffix=suffix, overwrite=args.overwrite - ) + upgrade_db(dbfile, suffix=suffix, overwrite=args.overwrite) - new_db.commit() if __name__ == "__main__": main() diff --git a/logpyle/runalyzer.py b/logpyle/runalyzer.py index 825c011..e6dc6a7 100644 --- a/logpyle/runalyzer.py +++ b/logpyle/runalyzer.py @@ -458,6 +458,20 @@ def my_sprintf(format: str, arg: str) -> str: # }}} +def is_gathered(conn: sqlite3.Connection): + gathered = False + # get a list of tables with the name of 'runs' + res = list(conn.execute(""" + SELECT name + FROM sqlite_master + WHERE type='table' AND name='runs' + """)) + if len(res) == 1: + gathered = True + + return gathered + + def auto_gather(filenames: List[str]) -> sqlite3.Connection: # allow for creating ungathered files. # Check if database has been gathered, if not, create one in memory @@ -467,16 +481,7 @@ def auto_gather(filenames: List[str]) -> sqlite3.Connection: # check if any of the provided files have been gathered for f in filenames: db = sqlite3.connect(f) - cur = db.cursor() - - # get a list of tables with the name of 'runs' - res = list(cur.execute(""" - SELECT name - FROM sqlite_master - WHERE type='table' AND name='runs' - """)) - # there exists a table with the name of 'runs' - if len(res) == 1: + if is_gathered(db): gathered = True if gathered: diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 04396ef..43ee095 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -3,69 +3,61 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: + from logpyle.runalyzer import is_gathered tmp = conn.execute("select * from warnings").description warning_columns = [col[0] for col in tmp] - # check if any of the provided files have been gathered - gathered = False - # get a list of tables with the name of 'runs' - res = list(conn.execute(""" - SELECT name - FROM sqlite_master - WHERE type='table' AND name='runs' - """)) - if len(res) == 1: - gathered = True + # check if the provided connection has been gathered + gathered = is_gathered(conn) # ensure that warnings table has unixtime column - if ("unixtime" not in warning_columns): + if "unixtime" not in warning_columns: print("Adding a unixtime column in the warnings table") conn.execute(""" - ALTER TABLE warnings - ADD unixtime integer DEFAULT NULL; + ALTER TABLE warnings + ADD unixtime integer DEFAULT NULL; """) # ensure that warnings table has rank column # nowhere to grab the rank of the process that generated # the warning - if ("rank" not in warning_columns): + if "rank" not in warning_columns: print("Adding a rank column in the warnings table") conn.execute(""" - ALTER TABLE warnings - ADD rank integer DEFAULT NULL; + ALTER TABLE warnings + ADD rank integer DEFAULT NULL; """) + tables = [col[0] for col in conn.execute(""" + SELECT name + FROM sqlite_master + WHERE type='table' + """)] + print("Ensuring a logging table exists") - if gathered: - conn.execute(""" - CREATE TABLE IF NOT EXISTS logging ( - run_id integer, - rank integer, - step integer, - unixtime integer, - level text, - message text, - filename text, - lineno integer - )""") - else: + if "logging" not in tables: conn.execute(""" - CREATE TABLE IF NOT EXISTS logging ( - rank integer, - step integer, - unixtime integer, - level text, - message text, - filename text, - lineno integer - )""") + CREATE TABLE logging ( + rank integer, + step integer, + unixtime integer, + level text, + message text, + filename text, + lineno integer + )""") + if gathered: + conn.execute(""" + ALTER TABLE logging + ADD run_id integer; + """) return conn def upgrade_db( dbfile: str, suffix: str, overwrite: bool - ) -> sqlite3.Connection: + ) -> None: # original db files old_conn = sqlite3.connect(dbfile) @@ -92,6 +84,8 @@ def upgrade_db( new_conn = upgrade_conn(new_conn) - old_conn.close() + if old_conn != new_conn: + old_conn.close() - return new_conn + new_conn.commit() + new_conn.close() From a4302b1c9fe23150f461ffe8ae8613462caa2de6 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 30 Nov 2023 03:20:32 -0600 Subject: [PATCH 17/37] CI tests upgrades from v2 and v3 in seperate names --- .github/workflows/ci.yaml | 49 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 693d271..30b509c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -258,24 +258,6 @@ jobs: run: | pip install -e . - # test ungathered_v3 default name - upgrade-db .github/workflows/log_ungathered_v3.sqlite - - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather - runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather - - # test gathered_v3 default name - upgrade-db .github/workflows/log_gathered_v3.sqlite - - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather - runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather - # test ungathered_v2 default name upgrade-db .github/workflows/log_ungathered_v2.sqlite @@ -304,3 +286,34 @@ jobs: runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather + + - name: Upgrade V3 to V3 + run: | + pip install -e . + + # test ungathered_v3 default name + upgrade-db .github/workflows/log_ungathered_v3.sqlite + + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather + + # test gathered_v3 default name + upgrade-db .github/workflows/log_gathered_v3.sqlite + + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather + + # test gathered custom name + upgrade-db .github/workflows/log_gathered_v3.sqlite --suffix '_new' + + runalyzer .github/workflows/log_gathered_v3_new.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather + runalyzer .github/workflows/log_gathered_v3_new.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather + runalyzer .github/workflows/log_gathered_v3_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather + runalyzer .github/workflows/log_gathered_v3_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_gathered_v3_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather From b98e1a664e2db135352893c300a07db6dde0f1aa Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 30 Nov 2023 03:36:27 -0600 Subject: [PATCH 18/37] Mypy fixed return type --- logpyle/runalyzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logpyle/runalyzer.py b/logpyle/runalyzer.py index e6dc6a7..7c47a56 100644 --- a/logpyle/runalyzer.py +++ b/logpyle/runalyzer.py @@ -458,7 +458,7 @@ def my_sprintf(format: str, arg: str) -> str: # }}} -def is_gathered(conn: sqlite3.Connection): +def is_gathered(conn: sqlite3.Connection) -> bool: gathered = False # get a list of tables with the name of 'runs' res = list(conn.execute(""" From 6c22d24a15ee785ce1e1e73dd33a56d21364041d Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 30 Nov 2023 16:30:01 -0600 Subject: [PATCH 19/37] Small comment on upgrading V3 DBs --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 30b509c..c3d640d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -288,6 +288,8 @@ jobs: runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather - name: Upgrade V3 to V3 + # Tests upgrades on current version for stability and allows users + # to blindly upgrade databases safely run: | pip install -e . From 68222e0f1c28096694f6278695db75600c4e6b25 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 30 Nov 2023 18:35:44 -0600 Subject: [PATCH 20/37] Primative pytest test for upgrade_db --- test/test_upgrade_db.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/test_upgrade_db.py diff --git a/test/test_upgrade_db.py b/test/test_upgrade_db.py new file mode 100644 index 0000000..fdc071f --- /dev/null +++ b/test/test_upgrade_db.py @@ -0,0 +1,32 @@ +import sqlite3 + +from logpyle import (upgrade_db) + + +def test_upgrade_v2_v3(): + path = ".github/workflows/log_gathered_v2.sqlite" + suffix = "_pytest_upgrade" + # print(path.rsplit(".", 1)) + # assert False + filename, file_ext = path.rsplit(".", 1) + + # ensure it is V2 + conn = sqlite3.connect(filename + "." + file_ext) + try: + # should throw an exception because logging + # should not exist in a V2 database + print([ele for ele in conn.execute("select * from logging")]) + assert False, f"{filename} is a v3 database" + except sqlite3.OperationalError: + pass # v2 should not have a logging table + conn.close() + + upgrade_db.upgrade_db(path, suffix, False) + + # ensure it is V3 + conn = sqlite3.connect(filename + suffix + "." + file_ext) + try: + print([ele for ele in conn.execute("select * from logging")]) + except sqlite3.OperationalError: + assert False, f"{filename} is not a v3 database" + conn.close() From 95136fb47070ca388a78a3c66ea5d7d33fedad5a Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 30 Nov 2023 18:42:50 -0600 Subject: [PATCH 21/37] Flake8 --- test/test_upgrade_db.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_upgrade_db.py b/test/test_upgrade_db.py index fdc071f..587cd19 100644 --- a/test/test_upgrade_db.py +++ b/test/test_upgrade_db.py @@ -16,7 +16,7 @@ def test_upgrade_v2_v3(): # should throw an exception because logging # should not exist in a V2 database print([ele for ele in conn.execute("select * from logging")]) - assert False, f"{filename} is a v3 database" + raise AssertionError(f"{filename} is a v3 database") except sqlite3.OperationalError: pass # v2 should not have a logging table conn.close() @@ -28,5 +28,5 @@ def test_upgrade_v2_v3(): try: print([ele for ele in conn.execute("select * from logging")]) except sqlite3.OperationalError: - assert False, f"{filename} is not a v3 database" + raise AssertionError(f"{filename} is not a v3 database") conn.close() From 0d5305c2d2de503b58106c28e91e8f134a1224b1 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 30 Nov 2023 18:48:42 -0600 Subject: [PATCH 22/37] Flake8 isort --- test/test_upgrade_db.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_upgrade_db.py b/test/test_upgrade_db.py index 587cd19..7445348 100644 --- a/test/test_upgrade_db.py +++ b/test/test_upgrade_db.py @@ -1,6 +1,6 @@ import sqlite3 -from logpyle import (upgrade_db) +from logpyle import upgrade_db def test_upgrade_v2_v3(): @@ -15,7 +15,7 @@ def test_upgrade_v2_v3(): try: # should throw an exception because logging # should not exist in a V2 database - print([ele for ele in conn.execute("select * from logging")]) + print(list(conn.execute("select * from logging"))) raise AssertionError(f"{filename} is a v3 database") except sqlite3.OperationalError: pass # v2 should not have a logging table @@ -26,7 +26,7 @@ def test_upgrade_v2_v3(): # ensure it is V3 conn = sqlite3.connect(filename + suffix + "." + file_ext) try: - print([ele for ele in conn.execute("select * from logging")]) + print(list(conn.execute("select * from logging"))) except sqlite3.OperationalError: raise AssertionError(f"{filename} is not a v3 database") conn.close() From d13f9447f1d06242f0f88b8a839873441faa0c90 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Tue, 5 Dec 2023 10:44:48 -0600 Subject: [PATCH 23/37] Basic Documentation for runalyzer 'is_gathered' and upgrade_db 'upgrade_db' APIs --- doc/api.rst | 2 ++ logpyle/runalyzer.py | 15 +++++++++++++++ logpyle/upgrade_db.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/doc/api.rst b/doc/api.rst index 59e4d0a..cdcd3ff 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -2,3 +2,5 @@ API Documentation ================= .. automodule:: logpyle +.. automodule:: logpyle.runalyzer +.. automodule:: logpyle.upgrade_db diff --git a/logpyle/runalyzer.py b/logpyle/runalyzer.py index 5756252..9f2971b 100644 --- a/logpyle/runalyzer.py +++ b/logpyle/runalyzer.py @@ -1,4 +1,9 @@ #! /usr/bin/env python +""" +Runalyzer Functions +-------------------------------- +.. autofunction:: is_gathered +""" import code import sqlite3 @@ -459,6 +464,16 @@ def my_sprintf(format: str, arg: str) -> str: def is_gathered(conn: sqlite3.Connection) -> bool: + """ + The function checks whether a connection to an existing + database has been gathered. + + Parameters + ---------- + conn + SQLite3 connection object + """ + gathered = False # get a list of tables with the name of 'runs' res = list(conn.execute(""" diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 43ee095..613723f 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -1,3 +1,8 @@ +""" +Database Upgrade Functions +-------------------------------- +.. autofunction:: upgrade_db +""" import shutil import sqlite3 @@ -58,6 +63,35 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: def upgrade_db( dbfile: str, suffix: str, overwrite: bool ) -> None: + """ + + The function first connects to the original database . If the + `overwrite` parameter is True, it simply modifies the existing + database and uses the same file name for the upgraded database. + Otherwise, a new database is created with a separate filename + by appending the given suffix to the original file's base name + using `filename + suffix + "." + file_ext`. + + Next, the function prints a message indicating whether it is + overwriting or creating a new database and then proceeds to + upgrade the database schema version to 3. + + Parameters + ---------- + name + Quantity name. + + dbfile + A database file path + + suffix + a suffix to be appended to the filename for the + upgraded database + + overwrite + a boolean value indicating + whether to overwrite the original database or not + """ # original db files old_conn = sqlite3.connect(dbfile) From 0a962b907614b6c0ccd0e5d16ebe259843418d32 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Tue, 5 Dec 2023 11:02:46 -0600 Subject: [PATCH 24/37] fixed typo --- logpyle/upgrade_db.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 613723f..120e604 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -78,9 +78,6 @@ def upgrade_db( Parameters ---------- - name - Quantity name. - dbfile A database file path From b42e82f31423a098e2b5ee78d0f347fe94bbea4d Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Tue, 5 Dec 2023 11:30:30 -0600 Subject: [PATCH 25/37] PR functional changes addressed --- logpyle/runalyzer.py | 2 +- logpyle/upgrade_db.py | 16 +++++++--------- test/test_upgrade_db.py | 16 ++++++++-------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/logpyle/runalyzer.py b/logpyle/runalyzer.py index 9f2971b..724dc36 100644 --- a/logpyle/runalyzer.py +++ b/logpyle/runalyzer.py @@ -465,7 +465,7 @@ def my_sprintf(format: str, arg: str) -> str: def is_gathered(conn: sqlite3.Connection) -> bool: """ - The function checks whether a connection to an existing + Returns whether a connection to an existing database has been gathered. Parameters diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 120e604..61e9b28 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -3,9 +3,12 @@ -------------------------------- .. autofunction:: upgrade_db """ +import logging import shutil import sqlite3 +logger = logging.getLogger(__name__) + def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: from logpyle.runalyzer import is_gathered @@ -64,18 +67,13 @@ def upgrade_db( dbfile: str, suffix: str, overwrite: bool ) -> None: """ - - The function first connects to the original database . If the + Upgrade a database file to the most recent format. If the `overwrite` parameter is True, it simply modifies the existing database and uses the same file name for the upgraded database. Otherwise, a new database is created with a separate filename by appending the given suffix to the original file's base name using `filename + suffix + "." + file_ext`. - Next, the function prints a message indicating whether it is - overwriting or creating a new database and then proceeds to - upgrade the database schema version to 3. - Parameters ---------- dbfile @@ -97,7 +95,7 @@ def upgrade_db( # simply perform modifications on old connection new_conn_name = dbfile new_conn = old_conn - print(f"Overwriting Database: {new_conn_name}") + logger.info(f"Overwriting Database: {new_conn_name}") else: # seperate the filename and the extention @@ -109,9 +107,9 @@ def upgrade_db( new_conn = sqlite3.connect(new_conn_name) - print(f"Creating new Database: {new_conn_name}, a clone of {dbfile}") + logger.info(f"Creating new Database: {new_conn_name}, a clone of {dbfile}") - print(f"Upgrading {new_conn_name} to schema version 3") + logger.info(f"Upgrading {new_conn_name} to schema version 3") new_conn = upgrade_conn(new_conn) diff --git a/test/test_upgrade_db.py b/test/test_upgrade_db.py index 7445348..75634f4 100644 --- a/test/test_upgrade_db.py +++ b/test/test_upgrade_db.py @@ -1,3 +1,5 @@ +import os +import pytest import sqlite3 from logpyle import upgrade_db @@ -6,27 +8,25 @@ def test_upgrade_v2_v3(): path = ".github/workflows/log_gathered_v2.sqlite" suffix = "_pytest_upgrade" - # print(path.rsplit(".", 1)) - # assert False filename, file_ext = path.rsplit(".", 1) # ensure it is V2 conn = sqlite3.connect(filename + "." + file_ext) - try: + with pytest.raises(sqlite3.OperationalError): # should throw an exception because logging # should not exist in a V2 database print(list(conn.execute("select * from logging"))) - raise AssertionError(f"{filename} is a v3 database") - except sqlite3.OperationalError: - pass # v2 should not have a logging table conn.close() upgrade_db.upgrade_db(path, suffix, False) # ensure it is V3 - conn = sqlite3.connect(filename + suffix + "." + file_ext) + upgraded_name = filename + suffix + "." + file_ext + conn = sqlite3.connect(upgraded_name) try: print(list(conn.execute("select * from logging"))) except sqlite3.OperationalError: - raise AssertionError(f"{filename} is not a v3 database") + os.remove(upgraded_name) + raise AssertionError(f"{upgraded_name} is not a v3 database") conn.close() + os.remove(upgraded_name) From 399cfe277d917c63d2f770b337ab9e68a1dad142 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Tue, 5 Dec 2023 11:40:46 -0600 Subject: [PATCH 26/37] Added table to upgrade_db autodocs --- logpyle/upgrade_db.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 61e9b28..3ac2b54 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -2,6 +2,17 @@ Database Upgrade Functions -------------------------------- .. autofunction:: upgrade_db + +.. list-table:: Overview of known changes between schema versions + :widths: 25 25 50 + :header-rows: 1 + + * - Version 1 + - Version 2 + - Version 3 (current) + * - Initial Version + - Added ``warnings.rank`` + - Added ``warnings.unixtime``, ``logging`` """ import logging import shutil From a95e8fbfe6f64e7f44ac3bb7eb9986c74c749e49 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Tue, 5 Dec 2023 11:44:31 -0600 Subject: [PATCH 27/37] Isort --- test/test_upgrade_db.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_upgrade_db.py b/test/test_upgrade_db.py index 75634f4..b5f9d38 100644 --- a/test/test_upgrade_db.py +++ b/test/test_upgrade_db.py @@ -1,7 +1,8 @@ import os -import pytest import sqlite3 +import pytest + from logpyle import upgrade_db From 6769605df46b87b96f2211e7838cc2cc691bcccf Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 14 Dec 2023 19:26:27 -0600 Subject: [PATCH 28/37] Small doc changes from PR and now updates schema_version constant to 3 --- .github/workflows/ci.yaml | 10 ++++++++++ bin/runalyzer | 5 ++++- logpyle/runalyzer.py | 2 +- logpyle/upgrade_db.py | 13 +++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c3d640d..16d8c21 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -261,11 +261,14 @@ jobs: # test ungathered_v2 default name upgrade-db .github/workflows/log_ungathered_v2.sqlite + # utilize nogather flag to ensure schema is from modification + # instead of gathering, which builds schema v3 runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_ungathered_v2_upgrade.sqlite -c 'assert [l[0] for l in q("select schema_version")][0] == 3' # test gathered_v2 default name @@ -276,6 +279,7 @@ jobs: runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_gathered_v2_upgrade.sqlite -c 'assert [l[0] for l in q("select schema_version")][0] == 3' # test gathered custom name @@ -286,6 +290,7 @@ jobs: runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert [l[0] for l in q("select schema_version")][0] == 3' - name: Upgrade V3 to V3 # Tests upgrades on current version for stability and allows users @@ -296,11 +301,14 @@ jobs: # test ungathered_v3 default name upgrade-db .github/workflows/log_ungathered_v3.sqlite + # utilize nogather flag to ensure schema is from modification + # instead of gathering, which builds schema v3 runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'db.print_cursor(db.q("select * from warnings"))' --nogather runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from warnings").description])' --nogather runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_ungathered_v3_upgrade.sqlite -c 'assert [l[0] for l in q("select schema_version")][0] == 3' # test gathered_v3 default name upgrade-db .github/workflows/log_gathered_v3.sqlite @@ -310,6 +318,7 @@ jobs: runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_gathered_v3_upgrade.sqlite -c 'assert [l[0] for l in q("select schema_version")][0] == 3' # test gathered custom name upgrade-db .github/workflows/log_gathered_v3.sqlite --suffix '_new' @@ -319,3 +328,4 @@ jobs: runalyzer .github/workflows/log_gathered_v3_new.sqlite -c 'print([l[0] for l in q("select * from logging").description])' --nogather runalyzer .github/workflows/log_gathered_v3_new.sqlite -c 'assert "unixtime" in [l[0] for l in q("select * from warnings").description]' --nogather runalyzer .github/workflows/log_gathered_v3_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather + runalyzer .github/workflows/log_gathered_v3_new.sqlite -c 'assert [l[0] for l in q("select schema_version")][0] == 3' diff --git a/bin/runalyzer b/bin/runalyzer index e21dc30..58849e3 100755 --- a/bin/runalyzer +++ b/bin/runalyzer @@ -17,7 +17,10 @@ def main() -> None: parser.add_argument("--script", type=str, help="script file to read") parser.add_argument("--nogather", action="store_true", - help="do not automatically gather files") + help=""" + Do not automatically gather files. Primarily + used internally to view database schema. + """) args = parser.parse_args() from logpyle.runalyzer import make_runalyzer_symbols, make_wrapped_db diff --git a/logpyle/runalyzer.py b/logpyle/runalyzer.py index 724dc36..00782f8 100644 --- a/logpyle/runalyzer.py +++ b/logpyle/runalyzer.py @@ -533,7 +533,7 @@ def make_wrapped_db( if gather: db = auto_gather(filenames) else: - assert len(filenames) == 1, "Enable autogather to support multiple infiles" + assert len(filenames) == 1, "Enable autogather to support multiple input files" db = sqlite3.connect(filenames[0]) db.create_aggregate("stddev", 1, StdDeviation) # type: ignore[arg-type] db.create_aggregate("var", 1, Variance) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 3ac2b54..31341e8 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -2,6 +2,9 @@ Database Upgrade Functions -------------------------------- .. autofunction:: upgrade_db +.. note:: + Currently, upgrades all schema versions to version 3. + Upgrading from version 1 is untested. .. list-table:: Overview of known changes between schema versions :widths: 25 25 50 @@ -71,6 +74,16 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: ADD run_id integer; """) + from pickle import dumps + schema_version = 3 + value = bytes(dumps(schema_version)) + if gathered: + conn.execute("UPDATE runs SET schema_version=3") + # conn.execute("UPDATE runs SET schema_version = ?", (value,)) + else: + # conn.execute("UPDATE constants SET value=3 WHERE name='schema_version'") + conn.execute("UPDATE constants SET value = ? WHERE name='schema_version'", (value,)) + return conn From 0e64ec03850a84fd9bbca6ee20bd6abe210f8d42 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Thu, 14 Dec 2023 19:34:12 -0600 Subject: [PATCH 29/37] Flake8 --- logpyle/runalyzer.py | 3 ++- logpyle/upgrade_db.py | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/logpyle/runalyzer.py b/logpyle/runalyzer.py index 00782f8..e6242d6 100644 --- a/logpyle/runalyzer.py +++ b/logpyle/runalyzer.py @@ -533,7 +533,8 @@ def make_wrapped_db( if gather: db = auto_gather(filenames) else: - assert len(filenames) == 1, "Enable autogather to support multiple input files" + assert len(filenames) == 1, \ + "Enable autogather to support multiple input files" db = sqlite3.connect(filenames[0]) db.create_aggregate("stddev", 1, StdDeviation) # type: ignore[arg-type] db.create_aggregate("var", 1, Variance) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 31341e8..cb847cd 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -20,6 +20,7 @@ import logging import shutil import sqlite3 +from pickle import dumps logger = logging.getLogger(__name__) @@ -74,15 +75,13 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: ADD run_id integer; """) - from pickle import dumps schema_version = 3 value = bytes(dumps(schema_version)) if gathered: conn.execute("UPDATE runs SET schema_version=3") - # conn.execute("UPDATE runs SET schema_version = ?", (value,)) else: - # conn.execute("UPDATE constants SET value=3 WHERE name='schema_version'") - conn.execute("UPDATE constants SET value = ? WHERE name='schema_version'", (value,)) + conn.execute("UPDATE constants SET value = ? WHERE name='schema_version'", + (value,)) return conn From 80d74af859f022d7734dc85dc64a7c742f139e94 Mon Sep 17 00:00:00 2001 From: Mike Montano Date: Sun, 17 Dec 2023 10:22:37 -0600 Subject: [PATCH 30/37] upgrade_db function always uses schema version defined internally --- logpyle/upgrade_db.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index cb847cd..f1f8a3a 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -78,9 +78,10 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: schema_version = 3 value = bytes(dumps(schema_version)) if gathered: - conn.execute("UPDATE runs SET schema_version=3") + conn.execute("UPDATE runs SET schema_version=?", + (schema_version,)) else: - conn.execute("UPDATE constants SET value = ? WHERE name='schema_version'", + conn.execute("UPDATE constants SET value=? WHERE name='schema_version'", (value,)) return conn From 83f3814063d5572cc074cfd2b7255200317655c2 Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Fri, 5 Jan 2024 15:28:52 +0100 Subject: [PATCH 31/37] extend version table --- logpyle/upgrade_db.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index f1f8a3a..b3e28f3 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -3,19 +3,22 @@ -------------------------------- .. autofunction:: upgrade_db .. note:: + Currently, upgrades all schema versions to version 3. - Upgrading from version 1 is untested. - -.. list-table:: Overview of known changes between schema versions - :widths: 25 25 50 - :header-rows: 1 - - * - Version 1 - - Version 2 - - Version 3 (current) - * - Initial Version - - Added ``warnings.rank`` - - Added ``warnings.unixtime``, ``logging`` + Upgrading from version <=1 is untested. + +.. table:: Overview of known changes between schema versions + + ============== =========================== ======= + Schema version Logpyle version Changes + ============== =========================== ======= + 0 pre v1 (``pytools.log``) Initial Version + 1 v1 -- v9 (``pytools.log``) Added ``warnings`` table + 2 v10 -- 2023.1 Added ``warnings.rank`` column + 3 2023.2 -- Added ``warnings.unixtime`` column + and ``logging`` table + ============== =========================== ======= + """ import logging import shutil From 32b5c448a052aee178f289d61f6421e4c4ccfb5a Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Fri, 5 Jan 2024 15:29:47 +0100 Subject: [PATCH 32/37] change print to logger --- logpyle/upgrade_db.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index b3e28f3..6b3685c 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -38,7 +38,7 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: # ensure that warnings table has unixtime column if "unixtime" not in warning_columns: - print("Adding a unixtime column in the warnings table") + logger.info("Adding a unixtime column in the warnings table") conn.execute(""" ALTER TABLE warnings ADD unixtime integer DEFAULT NULL; @@ -48,7 +48,7 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: # nowhere to grab the rank of the process that generated # the warning if "rank" not in warning_columns: - print("Adding a rank column in the warnings table") + logger.info("Adding a rank column in the warnings table") conn.execute(""" ALTER TABLE warnings ADD rank integer DEFAULT NULL; @@ -60,7 +60,7 @@ def upgrade_conn(conn: sqlite3.Connection) -> sqlite3.Connection: WHERE type='table' """)] - print("Ensuring a logging table exists") + logger.info("Ensuring a logging table exists") if "logging" not in tables: conn.execute(""" CREATE TABLE logging ( From 1f15bd098e6461e3bd756d9c90b5425f38c2ffd6 Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Fri, 5 Jan 2024 15:37:50 +0100 Subject: [PATCH 33/37] clarify schema_version --- logpyle/upgrade_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 6b3685c..3924284 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -12,7 +12,7 @@ ============== =========================== ======= Schema version Logpyle version Changes ============== =========================== ======= - 0 pre v1 (``pytools.log``) Initial Version + 0 pre v1 (``pytools.log``) Initial version, no schema_version yet 1 v1 -- v9 (``pytools.log``) Added ``warnings`` table 2 v10 -- 2023.1 Added ``warnings.rank`` column 3 2023.2 -- Added ``warnings.unixtime`` column From aacadd1f86d22e85afc59f432cfdaf5224e8d195 Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Fri, 5 Jan 2024 16:08:53 +0100 Subject: [PATCH 34/37] spelling --- logpyle/upgrade_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 3924284..3ecccba 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -125,7 +125,7 @@ def upgrade_db( logger.info(f"Overwriting Database: {new_conn_name}") else: - # seperate the filename and the extention + # separate the filename and the extension filename, file_ext = dbfile.rsplit(".", 1) new_conn_name = filename + suffix + "." + file_ext From f6b656743acf4d6f435067a16a7afcc387a62e48 Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Fri, 5 Jan 2024 16:13:26 +0100 Subject: [PATCH 35/37] better table --- logpyle/upgrade_db.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/logpyle/upgrade_db.py b/logpyle/upgrade_db.py index 3ecccba..7afd526 100644 --- a/logpyle/upgrade_db.py +++ b/logpyle/upgrade_db.py @@ -9,15 +9,16 @@ .. table:: Overview of known changes between schema versions - ============== =========================== ======= + ============== =========================== ================================== Schema version Logpyle version Changes - ============== =========================== ======= - 0 pre v1 (``pytools.log``) Initial version, no schema_version yet + ============== =========================== ================================== + 0 pre v1 (``pytools.log``) Initial version, no schema_version + yet 1 v1 -- v9 (``pytools.log``) Added ``warnings`` table 2 v10 -- 2023.1 Added ``warnings.rank`` column 3 2023.2 -- Added ``warnings.unixtime`` column and ``logging`` table - ============== =========================== ======= + ============== =========================== ================================== """ import logging From 8bf7b18b3b30d233d3309f681272a792cf251908 Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Fri, 5 Jan 2024 16:13:36 +0100 Subject: [PATCH 36/37] simplify is_gathered --- logpyle/runalyzer.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/logpyle/runalyzer.py b/logpyle/runalyzer.py index e6242d6..6250bff 100644 --- a/logpyle/runalyzer.py +++ b/logpyle/runalyzer.py @@ -474,17 +474,18 @@ def is_gathered(conn: sqlite3.Connection) -> bool: SQLite3 connection object """ - gathered = False # get a list of tables with the name of 'runs' res = list(conn.execute(""" SELECT name FROM sqlite_master WHERE type='table' AND name='runs' """)) + assert len(res) <= 1 + if len(res) == 1: - gathered = True + return True - return gathered + return False def auto_gather(filenames: List[str]) -> sqlite3.Connection: From 1e35b4aaf229b23e82ff9cc1211fe94b47d9c846 Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Fri, 5 Jan 2024 16:18:35 +0100 Subject: [PATCH 37/37] CI updates --- .github/workflows/ci.yaml | 79 ++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 16d8c21..2a9459d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,7 +11,7 @@ jobs: flake8: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -31,7 +31,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} uses: actions/setup-python@v4 with: @@ -150,40 +150,37 @@ jobs: docs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - name: "Main Script" - run: | - curl -L -O https://tiker.net/ci-support-v0 - . ci-support-v0 - build_py_project_in_venv - build_docs + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.x' + - name: "Main Script" + run: | + curl -L -O https://tiker.net/ci-support-v0 + . ci-support-v0 + build_py_project_in_venv + build_docs mypy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - name: "Main Script" - run: | - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/main/prepare-and-run-mypy.sh - export EXTRA_INSTALL="pytools numpy types-psutil pymbolic" - . ./prepare-and-run-mypy.sh python3 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.x' + - name: "Main Script" + run: | + curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/main/prepare-and-run-mypy.sh + export EXTRA_INSTALL="pytools numpy types-psutil pymbolic" + . ./prepare-and-run-mypy.sh python3 pytest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-python@v4 - with: - python-version: '3.x' + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.x' - name: Run tests run: | @@ -198,10 +195,10 @@ jobs: coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: - python-version: '3.x' + python-version: '3.x' - name: Compare coverage with 'main' branch run: | set -x @@ -228,11 +225,10 @@ jobs: htmlalyzer: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-python@v4 - with: - python-version: '3.x' + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.x' - name: Run run: | @@ -248,13 +244,12 @@ jobs: name: Upgrade-Database runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-python@v4 - with: - python-version: '3.x' + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.x' - - name: Upgrade V2 to V3 + - name: Upgrade v2 to v3 run: | pip install -e . @@ -292,7 +287,7 @@ jobs: runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert "rank" in [l[0] for l in q("select * from warnings").description]' --nogather runalyzer .github/workflows/log_gathered_v2_new.sqlite -c 'assert [l[0] for l in q("select schema_version")][0] == 3' - - name: Upgrade V3 to V3 + - name: Upgrade v3 to v3 # Tests upgrades on current version for stability and allows users # to blindly upgrade databases safely run: |