Skip to main content

A Pythonic, zero-dependency vector and table library for interactive data exploration

Project description

serif

License: MIT Tests

Python in, Python out. Allowed to raise, not allowed to lie.

Serif is typed vectors and tables for Python, built around two promises: touching your data should feel like ordinary Python, and ambiguous operations should fail loudly.

Values stay Python values — int, float, str, date, None — so there is nothing to convert, unwrap, or remember. And serif does not silently coerce, mutate, or guess. When an operation has no clear meaning, it raises.

Vector provides the foundation. Table is the primary interface for exploration, modeling, and analysis.

30-Second Example

from serif import Table

t = Table({
    "price ($)": [10, 20, 30],
    "quantity":  [4, 5, 6]
})

t >>= {'total': t.price * t.quantity}
t >>= {'tax': t.total * 0.1}

t
# 'price ($)'   quantity   total      tax
#      .price  .quantity  .total     .tax
#       [int]      [int]   [int]  [float]
#          10          4      40      4.0
#          20          5     100     10.0
#          30          6     180     18.0
#
# 3×4 table <int:3, float>

Installation

pip install serif

Zero dependencies — pip freeze in a fresh environment shows exactly one line.

Quickstart

Vectors

from serif import Vector

a = Vector([1, 2, 3, 4, 5])

a * 2         # 2, 4, 6, 8, 10
a > 3         # False, False, False, True, True
a[a > 3]      # 4, 5 — boolean masks filter
a.sum()       # 15 — a plain Python int

Tables

from serif import Table

t = Table({
    "first name": ["ann", "bo", "cy"],
    "price ($)":  [10, 20, 30],
})

t.price * 2                    # names sanitize for dot access
t >>= {'total': t.price * 2}   # add a column
t[t.price > 15]                # masks filter rows

t._                            # what do I have again?
# .first_name   str   'first name'
# .price        int   'price ($)'
# .total        int

None means missing

Element-wise, unknown in is unknown out. Aggregates summarize what you know. And a verdict needs evidence — all()/any() over zero valid values raise rather than guess.

v = Vector([10, None, 30])

v + 1        # 11, None, 31
v > 15       # False, None, True
v.sum()      # 40
len(v)       # 3

Vector([None, None]).any()                 # raises SerifEmptyReductionError
Vector([None, None]).any(on_empty=False)   # False — you supplied the verdict

Joins and aggregation

customers = Table({'id': [1, 2, 3], 'name': ['Ann', 'Bo', 'Cy']})
scores    = Table({'id': [2, 3, 4], 'score': [85, 90, 95]})

customers.inner_join(scores, left_on='id', right_on='id')
# id, name, score — matched key columns are not duplicated

sales = Table({'customer': ['A', 'B', 'A'], 'amount': [100, 200, 150]})

sales.aggregate(
    groupby=sales.customer,
    aggregations={'total': sales.amount.sum, 'n': len},
)
# customer  total  n
#        A    250  2
#        B    200  1

CSV and Parquet

from serif import read_csv, read_parquet

t = read_csv("sales.csv")        # types inferred, headers sanitized for dot access
t.to_parquet("sales.parquet")    # ints, dates, and nulls arrive intact
u = read_parquet("sales.parquet")
recent = u[u.date >= cutoff]      # remaining columns load through this mask

read_parquet reads the footer first and materializes columns only when they are touched. Boolean filtering stays ordinary Serif filtering: the concrete mask is carried into columns that have not been read yet, so the first fully materialized table can be the filtered one. Keep the source file readable and unchanged until the table has materialized.

Documentation

License

MIT

Contributing

See CONTRIBUTING.md and CODE_OF_CONDUCT.md.

Project details


Download files

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

Source Distribution

serif-0.2.0.tar.gz (227.5 kB view details)

Uploaded Source

Built Distribution

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

serif-0.2.0-py3-none-any.whl (135.3 kB view details)

Uploaded Python 3

File details

Details for the file serif-0.2.0.tar.gz.

File metadata

  • Download URL: serif-0.2.0.tar.gz
  • Upload date:
  • Size: 227.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for serif-0.2.0.tar.gz
Algorithm Hash digest
SHA256 41dfaf4325141e2b7733ae9ee3d316df95a34526fc242c8f4eaa94cf98fc3e0f
MD5 bb02458a2344c4c48b98b6965276553a
BLAKE2b-256 0b720f5725064bc78d8d52b3d535aa94334d5d60f0518c6552b31317cb6b7681

See more details on using hashes here.

File details

Details for the file serif-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: serif-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 135.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for serif-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0420f1382b7bd6911345b242ae985cba13ec3168283e22dec21a18ff6e9dc63e
MD5 cb65eb647e5c1fcb3ea3e8765e183cb7
BLAKE2b-256 ec0d0d734953c61a1147a2989eb6a922ba6781bf5f435274b4187df48e4a155e

See more details on using hashes here.

Supported by

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