Exporters¶
Base infrastructure¶
ExportRecord, ExportMetadata, and WriteSpec are the data structures that flow through the export pipeline. ExportMetadata accumulates records for every EXPORT call in a script run; WriteSpec captures per-file encoding and path configuration. These are used internally by all format writers — you only need to understand them if you are writing a new exporter. See Adding Exporters for a step-by-step guide.
Base export infrastructure — metadata tracking and write specifications.
Provides:
- :class:
ExportRecord— records details of a single export operation (query name, output file, optional zip file, description, script location, database info). - :class:
ExportMetadata— collection of :class:ExportRecordobjects; can write itself as a JSON metadata file. - :class:
WriteSpec— specification for a deferred write operation (message text, file path, encoding) used by halt/cancel hooks.
__all__ = ['ExportMetadata', 'ExportRecord', 'WriteSpec']
module-attribute
¶
ExportMetadata()
¶
Collection of :class:ExportRecord objects; can write itself as JSON.
Accumulates export records during a script run and provides them to the EXPORT METADATA metacommand for serialisation.
Initialise an empty record collection.
colhdrs = ['query', 'filename', 'zipfilename', 'file_path', 'description', 'script', 'script_path', 'script_line', 'script_date', 'database', 'server', 'username']
class-attribute
instance-attribute
¶
recordlist = []
instance-attribute
¶
add(exp_record)
¶
Append an export record to the collection.
get()
¶
Return column headers and all not-yet-exported records, marking them exported.
get_all()
¶
Return column headers and every record regardless of prior export state.
ExportRecord(queryname, outfile, zipfile=None, description=None)
¶
Records the details of a single EXPORT operation for metadata tracking.
Captures the query name, output file path, optional zip file, user description, originating script location, and database connection info.
Record export details for the given query name and output file.
WriteSpec(message, dest=None, tee=None, repeatable=False)
¶
Specification for a deferred WRITE operation used by halt/cancel hooks.
Stores a message, optional destination file, tee flag, and repeatability setting. Resolved and executed later by the hook machinery.
Exporter Protocol definitions for execsql.
Defines two @runtime_checkable Protocols that describe the two main
exporter calling conventions used throughout the exporters package:
- :class:
QueryExporter— functions that accept a SQL SELECT statement and a database connection, execute the query, and write the results. - :class:
RowsetExporter— functions that accept pre-fetched column headers and rows and write them to an output destination.
These Protocols capture the most common parameter signature. Several
concrete exporters have additional keyword arguments (tablename,
sheetname, template_file, write_types, and_val, etc.)
that extend the base contract. Such functions remain structurally
compatible: they satisfy the Protocol when called with the base
arguments, and the extra parameters have defaults or are supplied by
the dispatch layer.
.. note::
The io_export.py dispatch chain is not refactored here.
These Protocols exist as a documentation and static-type-checking
layer that formalises the implicit interface already present in the
codebase.
__all__ = ['QueryExporter', 'RowsetExporter']
module-attribute
¶
QueryExporter
¶
Bases: Protocol
Protocol for exporters that execute a query and write output.
The canonical signature is::
def __call__(
self,
select_stmt: str,
db: Any,
outfile: str,
append: bool = False,
desc: str | None = None,
zipfile: str | None = None,
) -> None: ...
Conforming functions¶
write_query_to_jsonwrite_query_to_htmlwrite_query_to_cgi_htmlwrite_query_to_latexwrite_query_to_valuesprettyprint_query(addsand_val)
Functions with extended signatures¶
write_query_to_xml(addstablename)write_query_to_json_ts(addswrite_types)write_query_to_ods(addssheetname, nozipfile)write_query_to_hdf5(addstable_name, nozipfile)write_query_to_duckdb(addstablename, nodesc/zipfile)write_query_to_sqlite(addstablename, nodesc/zipfile)report_query(addstemplate_file)write_queries_to_ods(table_listinstead ofselect_stmt)
__call__(select_stmt, db, outfile, append=False, desc=None, zipfile=None)
¶
RowsetExporter
¶
Bases: Protocol
Protocol for exporters that accept pre-fetched headers and rows.
The canonical signature is::
def __call__(
self,
outfile: str,
hdrs: list[str],
rows: Any,
append: bool = False,
desc: str | None = None,
zipfile: str | None = None,
) -> None: ...
Conforming functions¶
export_values
Functions with extended signatures¶
export_html(addsquerytext)export_cgi_html(addsquerytext)export_latex(addsquerytext)export_ods(addsquerytext,sheetname, nozipfile)prettyprint_rowset(usescolhdrs/output_dest, addsand_val)export_duckdb(addstablename, nodesc/zipfile)export_sqlite(addstablename, nodesc/zipfile)write_query_to_feather(minimal:outfile,headers,rowsonly)write_query_to_parquet(minimal:outfile,headers,rowsonly)write_query_raw(usesrowsource+db_encoding)write_query_b64(usesrowsourceonly)write_delimited_file(usesfilefmt,column_headers,rowsource,file_encoding)
__call__(outfile, hdrs, rows, append=False, desc=None, zipfile=None)
¶
Format writers¶
Each module below implements one or more output formats. Every writer follows the same signature: receive a SQL select_stmt string and a Database instance, stream rows via db.select_rowsource(), and write to a file or zip. See Adding Exporters to add a new format.
__all__ = ['LineDelimiter', 'CsvFile', 'CsvWriter', 'DelimitedWriter', 'write_delimited_file']
module-attribute
¶
CsvFile(csvfname, file_encoding, junk_header_lines=0)
¶
Bases: EncodedFile
Full delimited-file reader/writer with automatic format diagnosis.
Supports custom delimiters, quoting, encoding, junk-header skipping,
column-type inference, and ZIP output via :class:CsvWriter.
Open a CSV file path for later reading or writing.
blank_cols = []
instance-attribute
¶
csvfname = csvfname
instance-attribute
¶
delimiter = None
instance-attribute
¶
escapechar = None
instance-attribute
¶
junk_header_lines = junk_header_lines
instance-attribute
¶
lineformat_set = False
instance-attribute
¶
parse_errors = []
instance-attribute
¶
quotechar = None
instance-attribute
¶
table_data = None
instance-attribute
¶
CsvLine(line_text)
¶
Represent a single CSV line for delimiter diagnosis and parsing.
Store the raw line text and prepare delimiter-count storage.
delim_counts = {}
instance-attribute
¶
escchar = '\\'
class-attribute
instance-attribute
¶
item_errors = []
instance-attribute
¶
text = line_text
instance-attribute
¶
__str__()
¶
count_delim(delim)
¶
Count occurrences of the given delimiter in the line text.
delim_count(delim)
¶
Return the previously counted occurrence total for the given delimiter.
items(delim, qchar)
¶
Parse the line into a list of items, splitting on unquoted delimiters.
record_format_error(pos_no, errmsg)
¶
Append a parse error message annotated with its character position.
well_quoted_line(delim, qchar)
¶
Return a tuple of (all-well-quoted, quote-usage-count, uses-escape-char).
__repr__()
¶
column_headers()
¶
Return the first row of the file as a list of column header strings.
create_table(database_type, schemaname, tablename, pretty=False)
¶
Generate a CREATE TABLE SQL statement for this file's inferred schema.
data_table_def()
¶
Return a :class:DataTable describing the file's columns and types.
diagnose_delim(linestream, possible_delimiters=None, possible_quotechars=None)
¶
Analyse a line stream and return the detected (delimiter, quote char, escape char) tuple.
evaluate_column_types()
¶
Scan the file and populate table_data with inferred column types.
evaluate_line_format()
¶
Scan the file to auto-detect the delimiter, quote character, and escape character.
lineformat(delimiter, quotechar, escapechar)
¶
Explicitly set the delimiter, quote character, and escape character.
openclean(mode)
¶
Return an opened file object with the configured number of junk header lines skipped.
read_and_parse_line(f)
¶
Read and parse one line from an open file, returning a list of field values.
reader()
¶
Yield parsed rows from the file as lists of field values.
writer(append=False)
¶
Return a :class:CsvWriter configured with this file's format settings.
CsvWriter(filename, file_encoding, delim, quote, escchar, append=False)
¶
Opens a named file (or stdout) and exposes a row-oriented delimited-text writing API.
Open a file and prepare a delimited writer with the given format settings.
dwriter = DelimitedWriter(self.output, delim, quote, escchar)
instance-attribute
¶
output = sys.stdout
instance-attribute
¶
close()
¶
Close the underlying output file.
write(text_str)
¶
Write a raw string to the output file.
writerow(datarow)
¶
Format and write a single data row.
writerows(datarows)
¶
Format and write each row in an iterable.
DelimitedWriter(outfile, delim, quote, escchar)
¶
Low-level writer that formats data rows as delimited text and sends them to an open file object.
Wrap an open file object with a :class:LineDelimiter for row-by-row writing.
line_delimiter = LineDelimiter(delim, quote, escchar)
instance-attribute
¶
outfile = outfile
instance-attribute
¶
write(text_str)
¶
Write a raw string directly to the underlying file object.
writerow(datarow)
¶
Format one data row as delimited text and write it to the file.
writerows(datarows)
¶
Write each row in an iterable of data rows to the file.
LineDelimiter(delim, quote, escchar)
¶
Encapsulates delimiter, quote character, and escape rules for a single line format.
Initialise the line-format constants for a given delimiter/quote pair.
delimiter = delim
instance-attribute
¶
joinchar = delim if delim else ''
instance-attribute
¶
quote_all_text = _state.conf.quote_all_text if _state.conf else False
instance-attribute
¶
quotechar = quote
instance-attribute
¶
quotedquote = escchar + quote
instance-attribute
¶
delimited(datarow, add_newline=True)
¶
Format a sequence of values as a single delimited text line.
write_delimited_file(outfile, filefmt, column_headers, rowsource, file_encoding='utf8', append=False, zipfile=None)
¶
Write a query result set to a CSV, TSV, or other delimited text file.
__all__ = ['write_query_to_json', 'write_query_to_json_ts']
module-attribute
¶
write_query_to_json(select_stmt, db, outfile, append=False, desc=None, zipfile=None)
¶
Execute a SELECT and write the result set as a JSON array of objects.
write_query_to_json_ts(select_stmt, db, outfile, append=False, write_types=True, desc=None, zipfile=None)
¶
Execute a SELECT and write the result set as a JSON object with a top-level field-type schema.
__all__ = ['export_html', 'export_cgi_html', 'write_query_to_html', 'write_query_to_cgi_html']
module-attribute
¶
export_cgi_html(outfile, hdrs, rows, append=False, querytext=None, desc=None, zipfile=None)
¶
Write a CGI-style HTML fragment (Content-Type header + table) to a file or ZIP archive.
export_html(outfile, hdrs, rows, append=False, querytext=None, desc=None, zipfile=None)
¶
Write a complete HTML document containing a data table to a file or ZIP archive.
write_query_to_cgi_html(select_stmt, db, outfile, append=False, desc=None, zipfile=None)
¶
Execute a SELECT and write the result set as a CGI-style HTML fragment.
write_query_to_html(select_stmt, db, outfile, append=False, desc=None, zipfile=None)
¶
Execute a SELECT and write the result set as a standalone HTML document.
__all__ = ['prettyprint_query', 'prettyprint_rowset']
module-attribute
¶
prettyprint_query(select_stmt, db, outfile, append=False, and_val='', desc=None, zipfile=None)
¶
Execute a SELECT and write the result set as a column-aligned text table.
prettyprint_rowset(colhdrs, rows, output_dest, append=False, and_val='', desc=None, zipfile=None)
¶
Format a pre-fetched result set as a fixed-width human-readable text table and write it.
__all__ = ['write_query_raw', 'write_query_b64']
module-attribute
¶
write_query_b64(outfile, rowsource, append=False, zipfile=None)
¶
Decode base64 column data from a row source and write the raw bytes to a file or ZIP archive.
write_query_raw(outfile, rowsource, db_encoding, append=False, zipfile=None)
¶
Write raw binary column data from a row source directly to a file or ZIP archive.
__all__ = ['export_values', 'write_query_to_values']
module-attribute
¶
export_values(outfile, hdrs, rows, append=False, desc=None, zipfile=None)
¶
Write pre-fetched rows as SQL INSERT … VALUES statements to a file or ZIP archive.
write_query_to_values(select_stmt, db, outfile, append=False, desc=None, zipfile=None)
¶
Execute a SELECT and write the result set as SQL INSERT … VALUES statements.
__all__ = ['StrTemplateReport', 'JinjaTemplateReport', 'report_query']
module-attribute
¶
JinjaTemplateReport(template_file)
¶
Generates a report by rendering a Jinja2 template against the full data table.
Load and compile the Jinja2 template from the given file path.
infname = template_file
instance-attribute
¶
template = SandboxedEnvironment().from_string(fh.read())
instance-attribute
¶
__repr__()
¶
write_report(headers, data_dict_rows, output_dest, append=False, zipfile=None)
¶
Render the Jinja2 template with headers and datatable context and write the output.
StrTemplateReport(template_file)
¶
Generates a report by applying Python's :class:string.Template to each row of a data table.
Load and compile the template from the given file path.
report_query(select_stmt, db, outfile, template_file, append=False, zipfile=None)
¶
Execute a SELECT and render the result set through a str-template or Jinja2 template file.
__all__ = ['export_latex', 'write_query_to_latex']
module-attribute
¶
export_latex(outfile, hdrs, rows, append=False, querytext=None, desc=None, zipfile=None)
¶
Write pre-fetched rows as a LaTeX tabular environment to a file or ZIP archive.
write_query_to_latex(select_stmt, db, outfile, append=False, desc=None, zipfile=None)
¶
Execute a SELECT and write the result set as a LaTeX tabular table.
__all__ = ['write_query_to_markdown']
module-attribute
¶
write_query_to_markdown(select_stmt, db, outfile, append=False, desc=None, zipfile=None)
¶
Execute select_stmt and write the result set as a GFM pipe table.
Writes a GitHub-Flavored Markdown pipe table to outfile (or into zipfile when provided). Column widths are derived from the widest value in each column (including the header), so the table renders legibly in plain-text editors as well as in Markdown renderers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
select_stmt
|
str
|
SQL SELECT statement to execute. |
required |
db
|
Any
|
Database connection object exposing |
required |
outfile
|
str
|
Destination file path, or |
required |
append
|
bool
|
When |
False
|
desc
|
str | None
|
Optional human-readable description. When provided it is
written as an HTML comment ( |
None
|
zipfile
|
str | None
|
When set, write into this ZIP archive instead of a plain file. outfile becomes the entry name inside the archive. |
None
|
__all__ = ['OdsFile', 'export_ods', 'write_query_to_ods', 'write_queries_to_ods']
module-attribute
¶
OdsFile()
¶
Wrapper around the odfpy library for reading and writing OpenDocument Spreadsheet files.
Import odfpy and initialise the workbook state.
cell_style_names = []
instance-attribute
¶
filename = None
instance-attribute
¶
wbk = None
instance-attribute
¶
__repr__()
¶
add_row_to_sheet(datarow, of_table, header=False)
¶
Append a data row to an ODS table, applying header or body cell styles as appropriate.
add_sheet(of_table)
¶
Attach a prepared sheet object to the workbook's spreadsheet element.
close()
¶
Release the workbook reference without saving.
define_body_style()
¶
Register the body cell style in the workbook if not already defined.
define_header_style()
¶
Register the header cell style (bottom-bordered) in the workbook if not already defined.
define_iso_date_style()
¶
Register an ISO-8601 date number style in the workbook if not already defined.
define_iso_datetime_style()
¶
Register an ISO-8601 datetime number style in the workbook if not already defined.
new_sheet(sheetname)
¶
Create and return a detached sheet object that can later be added to the workbook.
open(filename)
¶
Open an existing ODS file or create a new one at the given path.
save_close()
¶
Serialise the workbook to disk and release all resources.
sheet_data(sheetname, junk_header_rows=0)
¶
Return all row data from the named sheet, optionally skipping leading junk rows.
sheet_named(sheetname)
¶
Return the sheet matching a name or 1-based integer index, or None if not found.
sheetnames()
¶
Return a list of worksheet names in the open workbook.
export_ods(outfile, hdrs, rows, append=False, querytext=None, sheetname=None, desc=None)
¶
Write a single-sheet ODS file from pre-fetched column headers and rows.
write_queries_to_ods(table_list, db, outfile, append=False, tee=False, desc=None)
¶
Write multiple tables/queries to separate sheets in a single ODS workbook.
write_query_to_ods(select_stmt, db, outfile, append=False, sheetname=None, desc=None)
¶
Execute a SELECT and write the result set as a single-sheet ODS spreadsheet.
__all__ = ['XlsFile', 'XlsxFile']
module-attribute
¶
XlsFile()
¶
Read-only wrapper around xlrd for importing legacy .xls spreadsheets.
Import xlrd and initialise file state; raises a fatal error if xlrd is absent.
datemode = 0
instance-attribute
¶
encoding = None
instance-attribute
¶
errlog = self.XlsLog()
instance-attribute
¶
filename = None
instance-attribute
¶
wbk = None
instance-attribute
¶
XlsLog()
¶
__repr__()
¶
open(filename, encoding=None, read_only=False)
¶
Open an existing .xls file for reading; raises XlsFileError if absent.
sheet_data(sheetname, junk_header_rows=0)
¶
Return all row data from the named sheet, optionally skipping leading junk rows.
sheet_named(sheetname)
¶
Return the sheet matching a name or 1-based integer, raising XlsFileError if absent.
sheetnames()
¶
Return the list of sheet objects in the open workbook.
XlsxFile()
¶
Read/write wrapper around openpyxl for .xlsx spreadsheets.
Import openpyxl and initialise file state; raises a fatal error if openpyxl is absent.
encoding = None
instance-attribute
¶
errlog = self.XlsxLog()
instance-attribute
¶
filename = None
instance-attribute
¶
read_only = False
instance-attribute
¶
wbk = None
instance-attribute
¶
XlsxLog()
¶
__repr__()
¶
close()
¶
Close the open workbook and reset all state attributes.
open(filename, encoding=None, read_only=False)
¶
Open an existing .xlsx file for reading; raises XlsxFileError if absent.
sheet_data(sheetname, junk_header_rows=0)
¶
Return all row data from the named sheet, optionally skipping leading junk rows.
sheet_named(sheetname)
¶
Return the sheet matching a name or 1-based integer index.
sheetnames()
¶
Return the list of worksheet names in the open workbook.
__all__ = ['write_query_to_xlsx', 'write_queries_to_xlsx']
module-attribute
¶
write_queries_to_xlsx(table_list, db, outfile, append=False, tee=False, desc=None)
¶
Write multiple tables/queries to separate worksheets in a single XLSX workbook.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
table_list
|
str
|
Comma-separated list of table names (optionally schema-qualified). |
required |
db
|
Any
|
An execsql database adapter with a |
required |
outfile
|
str
|
Destination |
required |
append
|
bool
|
If |
False
|
tee
|
bool
|
If |
False
|
desc
|
str | None
|
Optional description(s). A single string is applied to every sheet; a comma-separated string with the same count as table_list assigns individual descriptions per sheet. |
None
|
write_query_to_xlsx(select_stmt, db, outfile, append=False, desc=None, sheetname=None)
¶
Execute select_stmt and write the result to a single worksheet in an XLSX file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
select_stmt
|
str
|
SQL SELECT statement to execute. |
required |
db
|
Any
|
An execsql database adapter with a |
required |
outfile
|
str
|
Destination |
required |
append
|
bool
|
If |
False
|
desc
|
str | None
|
Optional human-readable description stored in the inventory sheet. |
None
|
sheetname
|
str | None
|
Name for the new worksheet. Defaults to |
None
|
__all__ = ['write_query_to_yaml']
module-attribute
¶
write_query_to_yaml(select_stmt, db, outfile, append=False, desc=None, zipfile=None)
¶
Execute select_stmt and write the result set to outfile as YAML.
The output is a YAML sequence of mappings — one mapping per row with
column headers as keys. Python types are preserved: integers stay
integers, floats stay floats, None becomes null.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
select_stmt
|
str
|
SQL SELECT statement to execute. |
required |
db
|
Any
|
Database connection object exposing |
required |
outfile
|
str
|
Destination file path, or |
required |
append
|
bool
|
When |
False
|
desc
|
str | None
|
Optional description string. Ignored in plain YAML output (YAML does not have a standard metadata header), but accepted for API consistency with other exporters. |
None
|
zipfile
|
str | None
|
When provided, write outfile as a member of this zip archive instead of writing to the filesystem directly. |
None
|
__all__ = ['write_query_to_feather', 'write_query_to_hdf5']
module-attribute
¶
write_query_to_feather(outfile, headers, rows)
¶
Write a row source as an Apache Arrow Feather v2 file using polars.
write_query_to_hdf5(table_name, select_stmt, db, outfile, append=False, desc=None)
¶
Execute a SELECT and write the result set to an HDF5 file using the tables library.
__all__ = ['export_sqlite', 'write_query_to_sqlite']
module-attribute
¶
export_sqlite(outfile, hdrs, rows, append, tablename)
¶
Write pre-fetched rows to a table in an SQLite database file, creating it if necessary.
write_query_to_sqlite(select_stmt, db, outfile, append, tablename)
¶
Execute a SELECT and write the result set to a named table in an SQLite database.
__all__ = ['export_duckdb', 'write_query_to_duckdb']
module-attribute
¶
export_duckdb(outfile, hdrs, rows, append, tablename)
¶
Write pre-fetched rows to a named table in a DuckDB database file.
write_query_to_duckdb(select_stmt, db, outfile, append, tablename)
¶
Execute a SELECT and write the result set to a named table in a DuckDB database.
__all__ = ['WriteableZipfile', 'ZipWriter']
module-attribute
¶
WriteableZipfile(zipfile_name, append=False)
¶
Thin ZipFile wrapper that accepts chunked string writes via an internal buffer.
Open (or create) a ZIP archive and allocate a write buffer.
buf = memoryview(bytearray(self.bufsize))
instance-attribute
¶
buflen = 0
instance-attribute
¶
bufsize = conf.zip_buffer_mb * 1024 * 1000
instance-attribute
¶
current_handle = None
instance-attribute
¶
zf = zipfile.ZipFile(zipfile_name, mode=zmode, compression=comp, compresslevel=9)
instance-attribute
¶
__del__()
¶
__enter__()
¶
__exit__(exc_type, exc_val, exc_tb)
¶
close()
¶
Close the open member (flushing the buffer) and finalise the ZIP archive.
close_member()
¶
Flush the buffer and close the currently open member file handle.
member_file(member_filename)
¶
Create a new member entry in the archive and open it for writing.
write(str_data)
¶
Buffer a UTF-8-encoded string for writing to the currently open member.
zip_buffer()
¶
Flush any buffered bytes to the currently open zip member file.
ZipWriter(zip_fname, member_fname, append=False)
¶
High-level write-only interface used by EXPORT metacommands to stream output into a ZIP archive.
Open the archive at zip_fname and begin a new member file named member_fname.
member = self.zwriter.member_file(member_fname)
instance-attribute
¶
member_fname = member_fname
instance-attribute
¶
zip_fname = zip_fname
instance-attribute
¶
zwriter = WriteableZipfile(self.zip_fname, append)
instance-attribute
¶
__enter__()
¶
__exit__(exc_type, exc_val, exc_tb)
¶
close()
¶
Close the zip member and finalise the archive.
write(str_data)
¶
Write a string to the current zip member.