Skip to main content

rollups

An iterable of dictionaries, with typed columns.

DataSet is a list of dictionary rows. Each row is an ordinary dict addressed by field name, and each column declares a Python type that its values convert to on first read. The container adds filtering, sorting, grouping, joining, pivoting, and summarizing.

A DataFrame stores each column as an array, so a row is a view built on demand and operations are written as vectors and masks. A DataSet stores each row as a dict, so for row in rows reads the stored object.

Use a DataFrame for rolling windows, matrix operations, and large row counts. Use a DataSet for records that arrive as dictionaries - a database cursor, a json payload, a csv - and for SQL-shaped operations on them. dataframe() and from_dataframe() convert between the two.

from rollups import DataSet

rows = DataSet([
    {'name': 'ana', 'group': 'a', 'amount': 120.5},
    {'name': 'bo',  'group': 'b', 'amount':  80.0},
    {'name': 'cy',  'group': 'a', 'amount':  45.25},
    ])
rows.columns = [('name', str), ('group', str), ('amount', float)]

for row in rows:
    if row.amount > 100:                       # a float, parsed on read
        print(f'{row.name} is over by {row.amount - 100:.2f}')

rows[0].name                       # 'ana'
rows[0]['name']                    # 'ana' - attribute or key
rows.sort_data('-amount')          # SQL order by, descending
rows.bucket('group', ['amount'])   # a: 165.75, b: 80.0

Install

From PyPI:

pip install rollups

Python 3.11 or later. It depends on pandas, libb-util, opendate, and prettytable.

Source: github.com/bissli/rollups.

To work on it:

git clone https://github.com/bissli/rollups
cd rollups
poetry install --extras test
python -m pytest -q

Typed columns

A column declares the type its values convert to, so a '120.5' read from a csv comes back as a float. The rows remain dicts. The types are metadata on the container.

A column is a (name, type) pair, declared or inferred:

records = [{'name': 'ana', 'amount': '120.5'}]

DataSet(records, columns=[('name', str), ('amount', float)])
DataSet(records)                             # types inferred from the rows
DataSet(records, infer_numeric_strings=True)   # '120.5' infers as float

Conversion is lazy: nothing converts at construction, and the first read of any row converts the whole container. Any class taking one argument serves as a column type.

Getting started covers the type system, the column operations, and the three kinds of copy.

What it does

Area Calls
Build DataSet(...), from_list, from_empty, from_dataframe
Read and write read / from_csv, write_csv, json, from_json, from_excel, write_excel
Columns add_column, remove_column, rename_column, cols, typs, colmap
Rows append, extend, pop, filter_data, dedupe, sample, partition
Order sort, sort_data, order, reverse
Reshape bucket, pivot, flatten, transpose, unwind
Combine join, diff, meld_datasets, match_rows
Series shift, backfill, pct_change
Present summary, add_summary_row, add_summary_column, pp
Screen apply_screen

Every one of these is documented under docs/.

Grouping

bucket is the SQL GROUP BY, and takes any callable as the aggregation:

rows.bucket('group', ['amount'])                 # sum, skipping None
rows.bucket('group', [('amount', max)])          # any callable
rows.bucket('group', [('amount', sum, 'total')]) # name the result
rows.bucket([], ['amount'])                      # one row, everything

pivot turns a column's values into columns of their own, flatten reverses that, and transpose swaps rows for columns. See Aggregating.

Joining

DataSet.join(left, 'key', right, 'key', 'left', bcol=['amount'])

Four join types, key columns that may be named differently on each side, per-side column selection and renaming, and a first flag for one-to-one matching. Where both sides carry a column, the left value wins unless it is None. See Joining.

Screening

A screen is a query language with one query per column. A screen is text, so it can come from a config file or a web form:

from rollups import apply_screen

apply_screen(rows, {'group': 'a|b', 'amount': '>50,<200'})
# rows is filtered in place

Comparison operators, regex search, None handling, and references to another column in the same row. See Screening.

Reading and writing

rows = DataSet.read('input.csv')      # type suffixes: name:s, age:i
rows.write_csv('output.csv')
rows.json(raw=True)                   # '[{"name": "ana"}]'

A csv header field may carry a type suffix - name:s, age:i, score:f, on:b, when:d - and a field without one reads as str. A line that will not decode is logged and skipped, and the read continues.

Excel goes through a backend the caller registers. This package imports no workbook library:

import rollups

rollups.register_excel_backend(my_excel_module)

See Reading and writing.

Presenting

totals = DataSet([
    {'name': 'ana', 'amount': 120.5},
    {'name': 'bo',  'amount':  80.0},
    ], columns=[('name', str), ('amount', float)])
totals.add_summary_row(label='Total')
print(totals.pp)
+-------+--------+
|  name | amount |
+-------+--------+
|  ana  | 120.50 |
|   bo  | 80.00  |
+-------+--------+
| Total | 200.50 |
+-------+--------+

The summary recomputes on every read, so filtering the rows and reading again gives the current total. See Summaries and output.

Working with pandas

DataSet.dataframe() and DataSet.from_dataframe() convert between the two representations, so a columnar step can run inside row-shaped work.

rollups.frame holds four functions that take and return pandas.DataFrame and do not reference DataSet:

from rollups import bucket_dataframe, join_dataframes

They answer differently from the DataSet versions on the same inputs: a malformed key raises where DataSet matches nothing silently, inner keeps left row order, and no result column is coerced to a reconstructed type. DataFrame-native join and group-by tabulates every difference.

Extending

Subclass DataSet, and every operation returns the subclass:

class Report(DataSet):

    def totals(self):
        return self.bucket([], [c for c, t in self.columns if t is float])

Every algorithm behind a method is also an exported function, so bucket_dataset(rows, ...) and rows.bucket(...) do the same thing. See Extending for the class-propagation rule, the workbook backend, and custom column types.

Documentation

Guide Covers
Getting started building a dataset, columns, the type system, copying
Rows adding, removing, ordering, filtering, and series operations
Screening the query language for filtering by column
Joining the four join types, first, diffing and melding
Aggregating bucket, pivot, flatten, transpose
Reading and writing csv, json, and the excel backend
Summaries and output summary rows, table rendering, paging
DataFrame-native the four functions that take and return frames
Architecture the modules, the layering, where a new function goes
Extending subclassing, the backend registry, custom types

Development

python -m pytest -q          # the suite
ruff check src/rollups/     # lint
bump2version patch           # never hand-edit the version

License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rollups-0.7.2.tar.gz (43.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rollups-0.7.2-py3-none-any.whl (45.4 kB view details)

Uploaded Python 3

File details

Details for the file rollups-0.7.2.tar.gz.

File metadata

  • Download URL: rollups-0.7.2.tar.gz
  • Upload date:
  • Size: 43.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.14.6 Linux/6.8.0-1060-aws

File hashes

Hashes for rollups-0.7.2.tar.gz
Algorithm Hash digest
SHA256 613e235067f720ddd09341a03b79be71f52a03f997fcd2e5818286bc45ae04f1
MD5 315d1f70a53f46f1f5987be7ad3f6934
BLAKE2b-256 995d3a2622e231becc6b258368dcc1b623a9d917639b17bfc3b83a63ee7a40db

See more details on using hashes here.

File details

Details for the file rollups-0.7.2-py3-none-any.whl.

File metadata

  • Download URL: rollups-0.7.2-py3-none-any.whl
  • Upload date:
  • Size: 45.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.14.6 Linux/6.8.0-1060-aws

File hashes

Hashes for rollups-0.7.2-py3-none-any.whl
Algorithm Hash digest
SHA256 b0b6e46e6681fec18fc209aea0adac2c26fac5744afad6dcc334c851e3fdea8a
MD5 7ff2be14d88c4ef79db1f1ab7e20b5a4
BLAKE2b-256 1e86dbf8131cf83e3f47b4f05ed556c378f7dd8abdc42a8096794bc92803a808

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.7.2 This release

2 files

0.7.1

2 files

0.7.0

2 files

0.0.1

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page