Module databased.dbmanager
Expand source code
import argparse
import sys
from pathlib import Path
from databased import DataBased, data_to_string
""" A command line tool to interact with a database file.
Works like a standard argparse based cli
except it will ask you for arguments indefinitely in a loop
instead of having to invoke the script with arguments over and over.
I.e. instead of "python dbManager.py -db database.db -f someString -t someTable",
just invoke "python dbManager.py" then a repeating "Enter command: " prompt will appear
and "-db database.db -f someString -t someTable" can be entered.
Note: a -db arg only needs to be provided once (if there is no default set) unless
you wish to change databases. So a subsequent command to the above
can just be entered as "-f someOtherString -t someTable".
This is just a quick template and can be customized by adding arguments and adding/overriding functions
for specific database projects."""
# Subclassing to prevent program exit when the -h/--help arg is passed.
class ArgParser(argparse.ArgumentParser):
def exit(self, status=0, message=None):
if message:
self._print_message(message, sys.stderr)
def get_args(command: str) -> argparse.Namespace:
parser = ArgParser()
parser.add_argument(
"-db",
"--dbname",
type=str,
default=None,
help="""Name of database file to use.
Required on the first loop if no default is set,
but subsequent loops will resuse the same database
unless a new one is provided through this arg.""",
)
parser.add_argument(
"-i",
"--info",
action="store_true",
help=""" Display table names, their respective columns, and how many records they contain.
If a -t/--tables arg is passed, just the columns and row count for those tables will be shown.""",
)
parser.add_argument(
"-t",
"--tables",
type=str,
nargs="*",
default=[],
help="""Limits commands to a specific list of tables.
Optional for some commands, required for others.
If this is the only arg given (besides -db if not already set),
the whole table will be printed to the terminal.""",
)
parser.add_argument(
"-c",
"--columns",
type=str,
nargs="*",
default=[],
help=""" Limits commands to a specific list of columns.
Optional for some commands, required for others.
If this and -t are the only args given
(besides -db if not already set), the whole table will be printed
to the terminal, but with only the columns provided with this arg.""",
)
parser.add_argument(
"-f",
"--find",
type=str,
default=None,
help=""" A substring to search the database for.
If a -c/--columns arg(s) is not given, the values will be matched against all columns.
Similarly, if a -t/--tables arg(s) is not given, the values will be searched for in all tables.""",
)
parser.add_argument(
"-sco",
"--show_count_only",
action="store_true",
help=""" Show the number of results returned by -f/--find,
but don't print the results to the terminal.""",
)
parser.add_argument(
"-d",
"--delete",
type=str,
nargs="*",
default=[],
help=""" A list of values to be deleted from the database.
A -c/--columns arg must be supplied.
A -t/--tables arg must be supplied.""",
)
parser.add_argument(
"-u",
"--update",
type=str,
default=None,
nargs=2,
help=""" Update a record in the database.
Expects two arguments: the current value and the new value.
A -c/--columns arg must be supplied.
A -t/--tables arg must be supplied.""",
)
parser.add_argument(
"-sb", "--sort_by", type=str, default=None, help="Column to sort results by."
)
args = parser.parse_args(command)
if args.dbname and not Path(args.dbname).exists():
raise Exception(f"{args.dbname} does not exist.")
return args
def info():
print("Getting database info...")
print()
if not args.tables:
args.tables = db.get_table_names()
results = []
for table in args.tables:
count = db.count(table)
columns = db.get_column_names(table)
results.append(
{
"table name": table,
"columns": ", ".join(columns),
"number of rows": count,
}
)
if args.sort_by and args.sort_by in results[0]:
results = sorted(results, key=lambda x: x[args.sort_by])
print(data_to_string(results))
def find():
print("Finding records... ")
print()
if not args.tables:
args.tables = db.get_table_names()
for table in args.tables:
results = db.find(table, args.find, args.columns)
if args.sort_by and args.sort_by in results[0]:
results = sorted(results, key=lambda x: x[args.sort_by])
if args.columns:
print(
f"{len(results)} results for '{args.find}' in '{', '.join(args.columns)}' column(s) of '{table}' table:"
)
else:
print(f"{len(results)} results for '{args.find}' in '{table}' table:")
if not args.show_count_only:
print(data_to_string(results))
print()
def delete():
if not args.tables:
raise ValueError("Missing -t/--tables arg for -d/--delete function.")
if not args.columns:
raise ValueError("Missing -c/--columns arg for -d/--delete function.")
print("Deleting records... ")
print()
num_deleted_records = 0
failed_deletions = []
for item in args.delete:
success = db.delete(args.tables[0], [(args.columns[0], item)])
if success:
num_deleted_records += success
else:
failed_deletions.append(item)
print(f"Deleted {num_deleted_records} record(s) from '{args.tables[0]}' table.")
if len(failed_deletions) > 0:
print(
f"Failed to delete the following {len(failed_deletions)} record(s) from '{args.tables[0]}' table:"
)
for fail in failed_deletions:
print(f" {fail}")
def update():
if not args.tables:
raise ValueError("Missing -t/--tables arg for -u/--update function.")
if not args.columns:
raise ValueError("Missing -c/--columns arg for -u/--update function.")
print("Updating record... ")
print()
if db.update(
args.tables[0],
args.columns[0],
args.update[1],
[(args.columns[0], args.update[0])],
):
print(
f"Updated '{args.columns[0]}' column from '{args.update[0]}' to '{args.update[1]}' in '{args.tables[0]}' table."
)
else:
print(
f"Failed to update '{args.columns[0]}' column from '{args.update[0]}' to '{args.update[1]}' in '{args.tables[0]}' table."
)
def print_table():
for table in args.tables:
rows = db.get_rows(
table, columns_to_return=args.columns, sort_by_column=args.sort_by
)
print(f"{table} table:")
print(data_to_string(rows))
if __name__ == "__main__":
sys.tracebacklimit = 0
while True:
try:
command = input("Enter command: ").split()
args = get_args(command)
if args.dbname:
dbname = args.dbname
with DataBased(dbpath=dbname) as db:
if args.info:
info()
elif args.find:
find()
elif args.delete:
delete()
elif args.update:
update()
else:
print_table()
except KeyboardInterrupt:
break
except Exception as e:
print(e)
Functions
def delete()
-
Expand source code
def delete(): if not args.tables: raise ValueError("Missing -t/--tables arg for -d/--delete function.") if not args.columns: raise ValueError("Missing -c/--columns arg for -d/--delete function.") print("Deleting records... ") print() num_deleted_records = 0 failed_deletions = [] for item in args.delete: success = db.delete(args.tables[0], [(args.columns[0], item)]) if success: num_deleted_records += success else: failed_deletions.append(item) print(f"Deleted {num_deleted_records} record(s) from '{args.tables[0]}' table.") if len(failed_deletions) > 0: print( f"Failed to delete the following {len(failed_deletions)} record(s) from '{args.tables[0]}' table:" ) for fail in failed_deletions: print(f" {fail}")
def find()
-
Expand source code
def find(): print("Finding records... ") print() if not args.tables: args.tables = db.get_table_names() for table in args.tables: results = db.find(table, args.find, args.columns) if args.sort_by and args.sort_by in results[0]: results = sorted(results, key=lambda x: x[args.sort_by]) if args.columns: print( f"{len(results)} results for '{args.find}' in '{', '.join(args.columns)}' column(s) of '{table}' table:" ) else: print(f"{len(results)} results for '{args.find}' in '{table}' table:") if not args.show_count_only: print(data_to_string(results)) print()
def get_args(command: str) ‑> argparse.Namespace
-
Expand source code
def get_args(command: str) -> argparse.Namespace: parser = ArgParser() parser.add_argument( "-db", "--dbname", type=str, default=None, help="""Name of database file to use. Required on the first loop if no default is set, but subsequent loops will resuse the same database unless a new one is provided through this arg.""", ) parser.add_argument( "-i", "--info", action="store_true", help=""" Display table names, their respective columns, and how many records they contain. If a -t/--tables arg is passed, just the columns and row count for those tables will be shown.""", ) parser.add_argument( "-t", "--tables", type=str, nargs="*", default=[], help="""Limits commands to a specific list of tables. Optional for some commands, required for others. If this is the only arg given (besides -db if not already set), the whole table will be printed to the terminal.""", ) parser.add_argument( "-c", "--columns", type=str, nargs="*", default=[], help=""" Limits commands to a specific list of columns. Optional for some commands, required for others. If this and -t are the only args given (besides -db if not already set), the whole table will be printed to the terminal, but with only the columns provided with this arg.""", ) parser.add_argument( "-f", "--find", type=str, default=None, help=""" A substring to search the database for. If a -c/--columns arg(s) is not given, the values will be matched against all columns. Similarly, if a -t/--tables arg(s) is not given, the values will be searched for in all tables.""", ) parser.add_argument( "-sco", "--show_count_only", action="store_true", help=""" Show the number of results returned by -f/--find, but don't print the results to the terminal.""", ) parser.add_argument( "-d", "--delete", type=str, nargs="*", default=[], help=""" A list of values to be deleted from the database. A -c/--columns arg must be supplied. A -t/--tables arg must be supplied.""", ) parser.add_argument( "-u", "--update", type=str, default=None, nargs=2, help=""" Update a record in the database. Expects two arguments: the current value and the new value. A -c/--columns arg must be supplied. A -t/--tables arg must be supplied.""", ) parser.add_argument( "-sb", "--sort_by", type=str, default=None, help="Column to sort results by." ) args = parser.parse_args(command) if args.dbname and not Path(args.dbname).exists(): raise Exception(f"{args.dbname} does not exist.") return args
def info()
-
Expand source code
def info(): print("Getting database info...") print() if not args.tables: args.tables = db.get_table_names() results = [] for table in args.tables: count = db.count(table) columns = db.get_column_names(table) results.append( { "table name": table, "columns": ", ".join(columns), "number of rows": count, } ) if args.sort_by and args.sort_by in results[0]: results = sorted(results, key=lambda x: x[args.sort_by]) print(data_to_string(results))
def print_table()
-
Expand source code
def print_table(): for table in args.tables: rows = db.get_rows( table, columns_to_return=args.columns, sort_by_column=args.sort_by ) print(f"{table} table:") print(data_to_string(rows))
def update()
-
Expand source code
def update(): if not args.tables: raise ValueError("Missing -t/--tables arg for -u/--update function.") if not args.columns: raise ValueError("Missing -c/--columns arg for -u/--update function.") print("Updating record... ") print() if db.update( args.tables[0], args.columns[0], args.update[1], [(args.columns[0], args.update[0])], ): print( f"Updated '{args.columns[0]}' column from '{args.update[0]}' to '{args.update[1]}' in '{args.tables[0]}' table." ) else: print( f"Failed to update '{args.columns[0]}' column from '{args.update[0]}' to '{args.update[1]}' in '{args.tables[0]}' table." )
Classes
class ArgParser (prog=None, usage=None, description=None, epilog=None, parents=[], formatter_class=argparse.HelpFormatter, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', add_help=True, allow_abbrev=True, exit_on_error=True)
-
Object for parsing command line strings into Python objects.
Keyword Arguments: - prog – The name of the program (default:
os.path.basename(sys.argv[0])
) - usage – A usage message (default: auto-generated from arguments) - description – A description of what the program does - epilog – Text following the argument descriptions - parents – Parsers whose arguments should be copied into this one - formatter_class – HelpFormatter class for printing help messages - prefix_chars – Characters that prefix optional arguments - fromfile_prefix_chars – Characters that prefix files containing additional arguments - argument_default – The default value for all arguments - conflict_handler – String indicating how to handle conflicts - add_help – Add a -h/-help option - allow_abbrev – Allow long options to be abbreviated unambiguously - exit_on_error – Determines whether or not ArgumentParser exits with error info when an error occursExpand source code
class ArgParser(argparse.ArgumentParser): def exit(self, status=0, message=None): if message: self._print_message(message, sys.stderr)
Ancestors
- argparse.ArgumentParser
- argparse._AttributeHolder
- argparse._ActionsContainer
Methods
def exit(self, status=0, message=None)
-
Expand source code
def exit(self, status=0, message=None): if message: self._print_message(message, sys.stderr)