-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Python comes with an sqlite3 library built-in, nothing to install #19
Comments
Also works with SQLite files and other connection types (not just in-memory). |
@jpivarski , seems introducing pandas into the flow seems to be little off track from the chapters. |
Pandas is only being used as a way to display it. A little helper function could pretty-print the few rows, but I don't know why that's not built into the def print_cursor(
cursor: sqlite3.Cursor,
*,
first: int = 5,
last: int = 5,
show_header: bool = True,
show_count: bool = True,
total_width: int = 80,
max_width: int = 15,
stream = sys.stdout,
):
# name of each column
header = [x[0] for x in cursor.description]
# width of the repr of each column
widths = [min(len(x), max_width) for x in header]
# iterate over the whole Cursor, but only keep `first + 2*last` rows in memory
first_rows = []
last_rows = []
row_count = 0
for row in cursor:
if len(first_rows) < first + last:
first_rows.append(row)
last_rows.append(row)
if len(last_rows) > last:
last_rows = last_rows[1:]
row_count += 1
if row_count <= first + last:
# if the number of rows <= `first + last`, show them all
rows = first_rows
else:
# otherwise, show the `first`, an ellipsis row, and then `last`
rows = first_rows[:first] + [[...] * len(header)] + last_rows
# represent rows with mutable lists so that we can replace them with reprs
rows = [list(x) for x in rows]
align = [">"] * len(header)
for row in rows:
assert len(row) == len(header), f"{len(row)} columns != {len(header)} columns"
for i, cell in enumerate(row):
# if all values are str or bytes (ignoring None), left-align
if cell != ... and isinstance(cell, (str, bytes)) and cell is not None:
align[i] = "<"
# replace data with their repr strings (except ellipsis)
row[i] = "..." if cell == ... else repr(cell)
# identify the maximum (string) width of each column, up to max_width
widths[i] = min(max(widths[i], len(row[i])), max_width)
# if the table is too wide, replace the last column with ellipsis
if sum(widths) + (len(widths) - 1) * 2 > total_width:
header[-1] = "..."
widths[-1] = 3
for row in rows:
row[-1] = "..."
# if the table is still too wide, remove columns
while sum(widths) + (len(widths) - 1) * 2 > total_width and len(header) > 1:
del header[-2]
del widths[-2]
for row in rows:
del row[-2]
# prepare a format string for each line of text
formatter = " | ".join(f"{{:{a}{w}s}}" for a, w in zip(align, widths))
# prepare the horizontal line between header and data
header_separator = "-+-".join("-" * w for w in widths)
if show_header:
# print the table column names and a horizontal line under it
stream.write(formatter.format(*[x[:w] for x, w in zip(header, widths)]) + "\n")
stream.write(header_separator + "\n")
for row in rows:
# print each table row
stream.write(formatter.format(*[x[:w] for x, w in zip(row, widths)]) + "\n")
if show_count:
# print the number of rows in another horizontal line
count = f"--- {row_count} rows ---"
stream.write(count + header_separator[len(count) :] + "\n") When you call print_cursor(db.execute("SELECT * FROM works")) you get
|
I used it in this tutorial: https://github.com/jpivarski-talks/2024-07-08-scipy-teen-track/blob/main/site/files/10-shakespeare.ipynb (in JupyterLite, in the students' browsers, so that they didn't need to install Python).
One thing that this interface doesn't have is a good way to display a table. However, Pandas can fill a DataFrame from an SQL query, and Pandas has a nice rendering in both console text and Jupyter HTML. So we can do dummy queries (
SELECT * FROM tablename
) to visualize small tables.The text was updated successfully, but these errors were encountered: