flat_file_renderers package

Submodules

Module contents

flat_file_renderers - render tabular/nested datasets into xlsx, csv, tsv, json, html or parquet files, zipped.

Only the dependency-free renderers (csv, tsv, json, html) are exported here, so importing this package never requires openpyxl or pyarrow. XlsxRenderer and ParquetRenderer are available from their own submodules and require the matching optional extra:

pip install flat-file-renderers[xlsx] # from flat_file_renderers.xlsx import XlsxRenderer pip install flat-file-renderers[parquet] # from flat_file_renderers.parquet import ParquetRenderer pip install flat-file-renderers[all] # both

class flat_file_renderers.BaseRenderer(context: dict[str, any])[source]

Bases: object

Base class for dataset renderers.

Defines the interface and basic structure for concrete renderers (CSV, Excel, Parquet, etc). Subclasses must implement the abstract render method to provide the file-generation logic.

context

Context dict used to render the file. May hold input data, a validated form, the requesting user, etc.

Type:

dict

Example

class CsvRenderer(BaseRenderer):
def render(self, *args, **kwargs) -> BytesIO:

…

renderer = CsvRenderer({‘columns’: [“Name”, “Age”], ‘rows’: [{“Name”: “Alice”, “Age”: “30”}]}) csv_file = renderer.render() with open(“data.csv”, “wb”) as f:

f.write(csv_file.getvalue())

property default_filename: str

Builds a default filename from the current date/time and the renderer’s extension.

Returns:

Suggested filename.

Return type:

str

property extension: str

Returns the default file extension produced by this renderer.

Returns:

File extension (e.g. ‘csv’, ‘xlsx’).

Return type:

str

abstractmethod render(*args, **kwargs) → BytesIO[source]

Abstract method that renders the data and produces the file.

Subclasses must implement this to provide the format-specific generation logic.

Returns:

In-memory generated file.

Return type:

BytesIO

write_zipfile(entries: list[ZipFileEntry]) → Path[source]

Compresses one or more files into a temporary ZIP file.

Parameters:

entries (list[ZipFileEntry]) – Entries to compress.

Returns:

Path to the generated ZIP file.

Return type:

Path

Examples: ```python zip_path = renderer.write_zipfile([ZipFileEntry(“data.csv”, Path(“/path/to/data.csv”))])

with open(zip_path, “rb”) as f:

zip_content = f.read()

from zipfile import ZipFile with ZipFile(zip_path, ‘r’) as zipf:

print(zipf.namelist())

# [‘data.csv’] ```

class flat_file_renderers.CsvRenderer(context: dict[str, any])[source]

Bases: FlatDelimitedRenderer

Renders data as CSV (Comma-Separated Values).

Uses comma as delimiter and ‘.csv’ extension.

class flat_file_renderers.FlatDelimitedRenderer(context: dict[str, any])[source]

Bases: BaseRenderer

Renders data as delimiter-separated values (CSV or TSV).

This base class exports tabular data into delimiter-separated files, such as CSV (comma) or TSV (tab).

The context must contain the ‘dataset’ key, which can be:
  • A QuerySet-like iterable: columns are inferred from the record fields.

  • A dict: must contain ‘rows’ (list of dicts) and ‘cols’ (list of column names).

  • A list: list of dicts, columns inferred from the first item’s keys.

Usage examples:

renderer = CsvRenderer({‘dataset’: {‘cols’: [“Name”, “Age”], ‘rows’: [{“Name”: “Alice”, “Age”: “30”}]}}) csv_file = renderer.render({‘dataset’: …}) with open(“data.csv”, “wb”) as f:

f.write(csv_file.read_bytes())

renderer = CsvRenderer({}) csv_file = renderer.render({‘dataset’: [{“Name”: “Alice”, “Age”: “30”}, {“Name”: “Bob”, “Age”: “25”}]})

property delimiter

Returns the delimiter used to separate values.

Returns:

Delimiter (comma by default).

Return type:

str

render(context: dict[str, any], *args, **kwargs) → Path[source]

Renders the data as delimiter-separated values and writes it into a temporary zip file on disk.

Parameters:
  • context (dict) – Dict holding the data to render. Must contain the ‘dataset’ key.

  • *args – Extra positional arguments.

  • **kwargs – Extra keyword arguments.

Returns:

Path to the compressed (zip) file containing the delimited file(s).

Return type:

Path

class flat_file_renderers.FlatDictListHelper[source]

Bases: object

Helper for renderers that deal with lists of plain dicts (or dict-like records), without deeply nested structures.

Provides methods to expand lists of dicts into flat columns and to normalize keys, so that renderers can handle tabular data consistently and without naming collisions. Particularly useful for renderers like CSV/TSV, which need to turn complex data into simple tabular rows.

static deep_flatten(row: dict, parent_key: str = '') → dict[source]

Recursively expands nested dicts and lists of dicts into a flat dict, using dot notation for nested keys.

Parameters:
  • row (dict) – Data row, possibly containing plain values, lists of dicts, or nested dicts.

  • parent_key (str) – Key prefix (used during recursion).

Returns:

Flat dict with all keys expanded.

Return type:

dict

Example

deep_flatten({“name”: “Alice”, “contacts”: [{“phone”: “1234”}, {“phone”: “5678”}]}) -> {“name”: “Alice”, “contacts.1.phone”: “1234”, “contacts.2.phone”: “5678”}

static expand_row(row: dict) → dict[source]

Expands lists of dicts into flat columns.

Discovers all columns, including expanded lists of dicts, and normalizes keys to avoid collisions. Lists of dicts are expanded into dot+index-notation columns, and keys are normalized by replacing ‘__’ with ‘.’.

Parameters:

row (dict) – Data row, holding plain values or lists of dicts.

Returns:

Flat dict where lists of dicts have been expanded into dot+index-notation columns.

Return type:

dict

Example

expand_row({“name”: “Alice”, “contacts”: [{“phone”: “1234”}, {“phone”: “5678”}]}) -> {“name”: “Alice”, “contacts.1.phone”: “1234”, “contacts.2.phone”: “5678”}

static extract_flat_columns(rows: list) → list[str][source]

Given a list of dicts (or record objects), returns the list of flat, normalized columns, including columns expanded from lists of dicts.

Parameters:

rows (list) – List of dicts or record/model objects representing the data rows.

Returns:

List of column names, including columns expanded from lists of dicts,

with normalized keys.

Return type:

list[str]

Example

rows = [

{“name”: “Alice”, “contacts”: [{“phone”: “1234”}, {“phone”: “5678”}]}, {“name”: “Bob”, “addresses”: [{“street”: “Street A”}, {“street”: “Street B”}]}

] # Output: [“name”, “contacts.1.phone”, “contacts.2.phone”, “addresses.1.street”, “addresses.2.street”]

static extract_rows_and_columns(context: dict[str, Any]) → tuple[list[Any], list[str]][source]

Extracts the rows and columns of a dataset present in the rendering context.

Accepts a dataset shaped as a dict (with ‘rows’/’cols’), a list, or any other iterable (e.g. a Django QuerySet or generator) - duck-typed via __iter__, no ORM import needed.

Parameters:

context (dict) – Context containing the ‘dataset’ key.

Returns:

Tuple of (rows, column names - if available).

Return type:

tuple[list, list]

Raises:

ValueError – If the context has no ‘dataset’ key, or its type isn’t supported.

static flatten_dataset(context: dict[str, Any]) → tuple[list[dict], list[str]][source]

Returns a flat version of the context’s dataset, with all rows and columns expanded and normalized.

Parameters:

context (dict) – Context containing the ‘dataset’ key.

Returns:

List of flat rows and list of column names.

Return type:

tuple[list[dict], list[str]]

static normalize_key(key: str) → str[source]

Replaces ‘__’ with ‘.’ in keys, to avoid clashing with the list-of-dicts dot notation.

Parameters:

key (str) – Key to normalize.

Returns:

Normalized key, with ‘__’ replaced by ‘.’.

Return type:

str

Example

normalize_key(“address__street”) -> “address.street” normalize_key(“person__contacts__1__phone”) -> “person.contacts.1.phone”

class flat_file_renderers.HtmlRenderer(context: dict[str, any])[source]

Bases: BaseRenderer

Renders data as HTML (an HTML table).

render(context: dict[str, any], *args, **kwargs) → Path[source]

Renders the data as HTML and writes it into a temporary zip file on disk.

Returns:

Path to the compressed (zip) file containing the .html file(s).

Return type:

Path

class flat_file_renderers.JsonRenderer(context: dict[str, any])[source]

Bases: BaseRenderer

Renders data as JSON Lines (a.k.a. NDJSON): one compact JSON object per line.

The same layout used by the OpenSearch/Elasticsearch bulk API. Consumers can read the file line by line instead of loading it whole, and the renderer itself writes record by record without materializing the dataset as a list.

render(context: dict[str, any], *args, **kwargs) → Path[source]

Renders the data as JSON Lines and writes it into a temporary zip file on disk.

Lists and QuerySet-like iterables produce one line per record. Any other dataset (a single record, or a dict with a “rows” key) produces a single line.

Returns:

Path to the compressed (zip) file containing the .jsonl file(s).

Return type:

Path

class flat_file_renderers.TsvRenderer(context: dict[str, any])[source]

Bases: FlatDelimitedRenderer

Renders data as TSV (Tab-Separated Values).

Uses tab as delimiter and ‘.tsv’ extension.

class flat_file_renderers.ZipFileEntry(zipfilealias: str, osfilepath: Path)[source]

Bases: object

flat_file_renderers.replace_crlf(val: str) → str[source]

Replaces embedded newline/carriage-return characters with a visible \n/\r marker.

Useful before writing a value into a single tabular cell (CSV/TSV/XLSX/HTML), where a raw embedded line break would otherwise corrupt the row layout.